Logo ROOT   6.18/05
Reference Guide
TBufferJSON.cxx
Go to the documentation of this file.
1//
2// Author: Sergey Linev 4.03.2014
3
4/*************************************************************************
5 * Copyright (C) 1995-2019, 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\class TBufferJSON
14\ingroup IO
15
16Class for serializing object to and from JavaScript Object Notation (JSON) format.
17It creates such object representation, which can be directly
18used in JavaScript ROOT (JSROOT) for drawing.
19
20TBufferJSON implements TBuffer interface, therefore most of
21ROOT and user classes can be converted into JSON.
22There are certain limitations for classes with custom streamers,
23which should be equipped specially for this purposes (see TCanvas::Streamer()
24as example).
25
26To perform conversion into JSON, one should use TBufferJSON::ToJSON method:
27~~~{.cpp}
28 TH1 *h1 = new TH1I("h1", "title", 100, 0, 10);
29 h1->FillRandom("gaus",10000);
30 TString json = TBufferJSON::ToJSON(h1);
31~~~
32
33To reconstruct object from the JSON string, one should do:
34~~~{.cpp}
35 TH1 *hnew = nullptr;
36 TBufferJSON::FromJSON(hnew, json);
37 if (hnew) hnew->Draw("hist");
38~~~
39JSON does not include stored class version, therefore schema evolution
40(reading of older class versions) is not supported. JSON should not be used as
41persistent storage for object data - only for live applications.
42
43All STL containers by default converted into JSON Array. Vector of integers:
44~~~{.cpp}
45 std::vector<int> vect = {1,4,7};
46 auto json = TBufferJSON::ToJSON(&vect);
47~~~
48Will produce JSON code "[1, 4, 7]".
49
50There are special handling for map classes like `map` and `multimap`.
51They will create Array of pair objects with "first" and "second" as data members. Code:
52~~~{.cpp}
53 std::map<int,string> m;
54 m[1] = "number 1";
55 m[2] = "number 2";
56 auto json = TBufferJSON::ToJSON(&m);
57~~~
58Will generate json string:
59~~~{.json}
60[
61 {"$pair" : "pair<int,string>", "first" : 1, "second" : "number 1"},
62 {"$pair" : "pair<int,string>", "first" : 2, "second" : "number 2"}
63]
64~~~
65In special cases map container can be converted into JSON object. For that key parameter
66must be `std::string` and compact parameter should be 5.
67Like in example:
68~~~{.cpp}
69std::map<std::string,int> data;
70data["name1"] = 11;
71data["name2"] = 22;
72
73auto json = TBufferJSON::ToJSON(&data, TBufferJSON::kMapAsObject);
74~~~
75Will produce JSON output:
76~~~
77{
78 "_typename": "map<string,int>",
79 "name1": 11,
80 "name2": 22
81}
82~~~
83Another possibility to enforce such conversion - add "JSON_object" into comment line of correspondent
84data member like:
85~~~{.cpp}
86class Container {
87 std::map<std::string,int> data; ///< JSON_object
88};
89~~~
90
91*/
92
93#include "TBufferJSON.h"
94
95#include <typeinfo>
96#include <string>
97#include <string.h>
98#include <locale.h>
99#include <cmath>
100#include <memory>
101
102#include <ROOT/RMakeUnique.hxx>
103
104#include "Compression.h"
105
106#include "TArrayI.h"
107#include "TObjArray.h"
108#include "TError.h"
109#include "TExMap.h"
110#include "TROOT.h"
111#include "TClass.h"
112#include "TClassTable.h"
113#include "TClassEdit.h"
114#include "TDataType.h"
115#include "TRealData.h"
116#include "TDataMember.h"
117#include "TMap.h"
118#include "TStreamerInfo.h"
119#include "TStreamerElement.h"
120#include "TFile.h"
121#include "TMemberStreamer.h"
122#include "TStreamer.h"
123#include "Riostream.h"
124#include "RZip.h"
125#include "TClonesArray.h"
126#include "TVirtualMutex.h"
127#include "TInterpreter.h"
129
130#include "json.hpp"
131
133
134enum { json_TArray = 100, json_TCollection = -130, json_TString = 110, json_stdstring = 120 };
135
136///////////////////////////////////////////////////////////////
137// TArrayIndexProducer is used to correctly create
138/// JSON array separators for multi-dimensional JSON arrays
139/// It fully reproduces array dimensions as in original ROOT classes
140/// Contrary to binary I/O, which always writes flat arrays
141
142class TArrayIndexProducer {
143protected:
144 Int_t fTotalLen{0};
145 Int_t fCnt{-1};
146 const char *fSepar{nullptr};
147 TArrayI fIndicies;
148 TArrayI fMaxIndex;
149 TString fRes;
150 Bool_t fIsArray{kFALSE};
151
152public:
153 TArrayIndexProducer(TStreamerElement *elem, Int_t arraylen, const char *separ) : fSepar(separ)
154 {
155 Bool_t usearrayindx = elem && (elem->GetArrayDim() > 0);
156 Bool_t isloop = elem && ((elem->GetType() == TStreamerInfo::kStreamLoop) ||
158 Bool_t usearraylen = (arraylen > (isloop ? 0 : 1));
159
160 if (usearrayindx && (arraylen > 0)) {
161 if (isloop) {
162 usearrayindx = kFALSE;
163 usearraylen = kTRUE;
164 } else if (arraylen != elem->GetArrayLength()) {
165 ::Error("TArrayIndexProducer", "Problem with JSON coding of element %s type %d", elem->GetName(),
166 elem->GetType());
167 }
168 }
169
170 if (usearrayindx) {
171 fTotalLen = elem->GetArrayLength();
172 fMaxIndex.Set(elem->GetArrayDim());
173 for (int dim = 0; dim < elem->GetArrayDim(); dim++)
174 fMaxIndex[dim] = elem->GetMaxIndex(dim);
175 fIsArray = fTotalLen > 1;
176 } else if (usearraylen) {
177 fTotalLen = arraylen;
178 fMaxIndex.Set(1);
179 fMaxIndex[0] = arraylen;
180 fIsArray = kTRUE;
181 }
182
183 if (fMaxIndex.GetSize() > 0) {
184 fIndicies.Set(fMaxIndex.GetSize());
185 fIndicies.Reset(0);
186 }
187 }
188
189 TArrayIndexProducer(TDataMember *member, Int_t extradim, const char *separ) : fSepar(separ)
190 {
191 Int_t ndim = member->GetArrayDim();
192 if (extradim > 0)
193 ndim++;
194
195 if (ndim > 0) {
196 fIndicies.Set(ndim);
197 fIndicies.Reset(0);
198 fMaxIndex.Set(ndim);
199 fTotalLen = 1;
200 for (int dim = 0; dim < member->GetArrayDim(); dim++) {
201 fMaxIndex[dim] = member->GetMaxIndex(dim);
202 fTotalLen *= member->GetMaxIndex(dim);
203 }
204
205 if (extradim > 0) {
206 fMaxIndex[ndim - 1] = extradim;
207 fTotalLen *= extradim;
208 }
209 }
210 fIsArray = fTotalLen > 1;
211 }
212
213 /// returns number of array dimensions
214 Int_t NumDimensions() const { return fIndicies.GetSize(); }
215
216 /// return array with current index
217 TArrayI &GetIndices() { return fIndicies; };
218
219 /// returns total number of elements in array
220 Int_t TotalLength() const { return fTotalLen; }
221
222 Int_t ReduceDimension()
223 {
224 // reduce one dimension of the array
225 // return size of reduced dimension
226 if (fMaxIndex.GetSize() == 0)
227 return 0;
228 Int_t ndim = fMaxIndex.GetSize() - 1;
229 Int_t len = fMaxIndex[ndim];
230 fMaxIndex.Set(ndim);
231 fIndicies.Set(ndim);
232 fTotalLen = fTotalLen / len;
233 fIsArray = fTotalLen > 1;
234 return len;
235 }
236
237 Bool_t IsArray() const { return fIsArray; }
238
239 Bool_t IsDone() const
240 {
241 // return true when iteration over all arrays indexes are done
242 return !IsArray() || (fCnt >= fTotalLen);
243 }
244
245 const char *GetBegin()
246 {
247 ++fCnt;
248 // return starting separator
249 fRes.Clear();
250 for (Int_t n = 0; n < fIndicies.GetSize(); ++n)
251 fRes.Append("[");
252 return fRes.Data();
253 }
254
255 const char *GetEnd()
256 {
257 // return ending separator
258 fRes.Clear();
259 for (Int_t n = 0; n < fIndicies.GetSize(); ++n)
260 fRes.Append("]");
261 return fRes.Data();
262 }
263
264 /// increment indexes and returns intermediate or last separator
265 const char *NextSeparator()
266 {
267 if (++fCnt >= fTotalLen)
268 return GetEnd();
269
270 Int_t cnt = fIndicies.GetSize() - 1;
271 fIndicies[cnt]++;
272
273 fRes.Clear();
274
275 while ((cnt >= 0) && (cnt < fIndicies.GetSize())) {
276 if (fIndicies[cnt] >= fMaxIndex[cnt]) {
277 fRes.Append("]");
278 fIndicies[cnt--] = 0;
279 if (cnt >= 0)
280 fIndicies[cnt]++;
281 continue;
282 }
283 fRes.Append(fIndicies[cnt] == 0 ? "[" : fSepar);
284 cnt++;
285 }
286 return fRes.Data();
287 }
288
289 nlohmann::json *ExtractNode(nlohmann::json *topnode, bool next = true)
290 {
291 if (!IsArray())
292 return topnode;
293 nlohmann::json *subnode = &((*((nlohmann::json *)topnode))[fIndicies[0]]);
294 for (int k = 1; k < fIndicies.GetSize(); ++k)
295 subnode = &((*subnode)[fIndicies[k]]);
296 if (next)
297 NextSeparator();
298 return subnode;
299 }
300};
301
302// TJSONStackObj is used to keep stack of object hierarchy,
303// stored in TBuffer. For instance, data for parent class(es)
304// stored in subnodes, but initial object node will be kept.
305
306class TJSONStackObj : public TObject {
307 struct StlRead {
308 Int_t fIndx{0}; //! index of object in STL container
309 Int_t fMap{0}; //! special iterator over STL map::key members
310 Bool_t fFirst{kTRUE}; //! is first or second element is used in the pair
311 nlohmann::json::iterator fIter; //! iterator for std::map stored as JSON object
312 const char *fTypeTag{nullptr}; //! type tag used for std::map stored as JSON object
313 nlohmann::json fValue; //! temporary value reading std::map as JSON
314 nlohmann::json *GetStlNode(nlohmann::json *prnt)
315 {
316 if (fMap <= 0)
317 return &(prnt->at(fIndx++));
318
319 if (fMap == 1) {
320 nlohmann::json *json = &(prnt->at(fIndx));
321 if (!fFirst) fIndx++;
322 json = &(json->at(fFirst ? "first" : "second"));
323 fFirst = !fFirst;
324 return json;
325 }
326
327 if (fIndx == 0) {
328 // skip _typename if appears
329 if (fTypeTag && (fIter.key().compare(fTypeTag) == 0))
330 ++fIter;
331 fValue = fIter.key();
332 fIndx++;
333 } else {
334 fValue = fIter.value();
335 ++fIter;
336 fIndx = 0;
337 }
338 return &fValue;
339 }
340 };
341
342public:
343 TStreamerInfo *fInfo{nullptr}; //!
344 TStreamerElement *fElem{nullptr}; //! element in streamer info
345 Bool_t fIsStreamerInfo{kFALSE}; //!
346 Bool_t fIsElemOwner{kFALSE}; //!
347 Bool_t fIsPostProcessed{kFALSE}; //! indicate that value is written
348 Bool_t fIsObjStarted{kFALSE}; //! indicate that object writing started, should be closed in postprocess
349 Bool_t fAccObjects{kFALSE}; //! if true, accumulate whole objects in values
350 std::vector<std::string> fValues; //! raw values
351 int fMemberCnt{1}; //! count number of object members, normally _typename is first member
352 int *fMemberPtr{nullptr}; //! pointer on members counter, can be inherit from parent stack objects
353 Int_t fLevel{0}; //! indent level
354 std::unique_ptr<TArrayIndexProducer> fIndx; //! producer of ndim indexes
355 nlohmann::json *fNode{nullptr}; //! JSON node, used for reading
356 std::unique_ptr<StlRead> fStlRead; //! custom structure for stl container reading
357 Version_t fClVersion{0}; //! keep actual class version, workaround for ReadVersion in custom streamer
358
359 TJSONStackObj() = default;
360
361 virtual ~TJSONStackObj()
362 {
363 if (fIsElemOwner)
364 delete fElem;
365 }
366
367 Bool_t IsStreamerInfo() const { return fIsStreamerInfo; }
368
369 Bool_t IsStreamerElement() const { return !fIsStreamerInfo && fElem; }
370
371 void PushValue(TString &v)
372 {
373 fValues.emplace_back(v.Data());
374 v.Clear();
375 }
376
377 void PushIntValue(Int_t v) { fValues.emplace_back(std::to_string(v)); }
378
379 ////////////////////////////////////////////////////////////////////////
380 /// returns separator for data members
381 const char *NextMemberSeparator()
382 {
383 return (!fMemberPtr || ((*fMemberPtr)++ > 0)) ? "," : "";
384 }
385
386 Bool_t IsJsonString() { return fNode && fNode->is_string(); }
387
388 ////////////////////////////////////////////////////////////////////////
389 /// checks if specified JSON node is array (compressed or not compressed)
390 /// returns length of array (or -1 if failure)
391 Int_t IsJsonArray(nlohmann::json *json = nullptr, const char *map_convert_type = nullptr)
392 {
393 if (!json)
394 json = fNode;
395
396 if (map_convert_type) {
397 if (!json->is_object()) return -1;
398 int sz = 0;
399 // count size of object, excluding _typename tag
400 for (auto it = json->begin(); it != json->end(); ++it) {
401 if ((strlen(map_convert_type)==0) || (it.key().compare(map_convert_type) != 0)) sz++;
402 }
403 return sz;
404 }
405
406 // normal uncompressed array
407 if (json->is_array())
408 return json->size();
409
410 // compressed array, full array length in "len" attribute, only ReadFastArray
411 if (json->is_object() && (json->count("$arr") == 1))
412 return json->at("len").get<int>();
413
414 return -1;
415 }
416
417 Int_t PopIntValue()
418 {
419 auto res = std::stoi(fValues.back());
420 fValues.pop_back();
421 return res;
422 }
423
424 std::unique_ptr<TArrayIndexProducer> MakeReadIndexes()
425 {
426 if (!fElem || (fElem->GetType() <= TStreamerInfo::kOffsetL) ||
427 (fElem->GetType() >= TStreamerInfo::kOffsetL + 20) || (fElem->GetArrayDim() < 2))
428 return nullptr;
429
430 auto indx = std::make_unique<TArrayIndexProducer>(fElem, -1, "");
431
432 // no need for single dimension - it can be handled directly
433 if (!indx->IsArray() || (indx->NumDimensions() < 2))
434 return nullptr;
435
436 return indx;
437 }
438
439 Bool_t IsStl() const { return fStlRead.get() != nullptr; }
440
441 Bool_t AssignStl(TClass *cl, Int_t map_convert, const char *typename_tag)
442 {
443 fStlRead = std::make_unique<StlRead>();
444 fStlRead->fMap = map_convert;
445 if (map_convert == 2) {
446 if (!fNode->is_object()) {
447 ::Error("TJSONStackObj::AssignStl", "when reading %s expecting JSON object", cl->GetName());
448 return kFALSE;
449 }
450 fStlRead->fIter = fNode->begin();
451 fStlRead->fTypeTag = typename_tag && (strlen(typename_tag) > 0) ? typename_tag : nullptr;
452 } else {
453 if (!fNode->is_array() && !(fNode->is_object() && (fNode->count("$arr") == 1))) {
454 ::Error("TJSONStackObj::AssignStl", "when reading %s expecting JSON array", cl->GetName());
455 return kFALSE;
456 }
457 }
458 return kTRUE;
459 }
460
461 nlohmann::json *GetStlNode()
462 {
463 return fStlRead ? fStlRead->GetStlNode(fNode) : fNode;
464 }
465
466 void ClearStl()
467 {
468 fStlRead.reset(nullptr);
469 }
470};
471
472////////////////////////////////////////////////////////////////////////////////
473/// Creates buffer object to serialize data into json.
474
476 : TBufferText(mode), fOutBuffer(), fOutput(nullptr), fValue(), fStack(), fSemicolon(" : "), fArraySepar(", "),
477 fNumericLocale(), fTypeNameTag("_typename")
478{
479 fOutBuffer.Capacity(10000);
480 fValue.Capacity(1000);
482
483 // checks if setlocale(LC_NUMERIC) returns others than "C"
484 // in this case locale will be changed and restored at the end of object conversion
485
486 char *loc = setlocale(LC_NUMERIC, 0);
487 if (loc && (strcmp(loc, "C") != 0)) {
488 fNumericLocale = loc;
489 setlocale(LC_NUMERIC, "C");
490 }
491}
492
493////////////////////////////////////////////////////////////////////////////////
494/// destroy buffer
495
497{
498 while (fStack.size() > 0)
499 PopStack();
500
501 if (fNumericLocale.Length() > 0)
502 setlocale(LC_NUMERIC, fNumericLocale.Data());
503
504 if (fSkipClasses)
505 delete fSkipClasses;
506}
507
508////////////////////////////////////////////////////////////////////////////////
509/// Converts object, inherited from TObject class, to JSON string
510/// Lower digit of compact parameter define formatting rules
511/// - 0 - no any compression, human-readable form
512/// - 1 - exclude spaces in the begin
513/// - 2 - remove newlines
514/// - 3 - exclude spaces as much as possible
515///
516/// Second digit of compact parameter defines algorithm for arrays compression
517/// - 0 - no compression, standard JSON array
518/// - 1 - exclude leading and trailing zeros
519/// - 2 - check values repetition and empty gaps
520///
521/// Maximal compression achieved when compact parameter equal to 23
522/// When member_name specified, converts only this data member
523
524TString TBufferJSON::ConvertToJSON(const TObject *obj, Int_t compact, const char *member_name)
525{
526 TClass *clActual = nullptr;
527 void *ptr = (void *)obj;
528
529 if (obj) {
530 clActual = TObject::Class()->GetActualClass(obj);
531 if (!clActual)
532 clActual = TObject::Class();
533 else if (clActual != TObject::Class())
534 ptr = (void *)((Long_t)obj - clActual->GetBaseClassOffset(TObject::Class()));
535 }
536
537 return ConvertToJSON(ptr, clActual, compact, member_name);
538}
539
540////////////////////////////////////////////////////////////////////////////////
541/// Set level of space/newline/array compression
542/// Lower digit of compact parameter define formatting rules
543/// - kNoCompress = 0 - no any compression, human-readable form
544/// - kNoIndent = 1 - remove indentation spaces in the begin of each line
545/// - kNoNewLine = 2 - remove also newlines
546/// - kNoSpaces = 3 - exclude all spaces and new lines
547///
548/// Second digit of compact parameter defines algorithm for arrays compression
549/// - 0 - no compression, standard JSON array
550/// - kZeroSuppression = 10 - exclude leading and trailing zeros
551/// - kSameSuppression = 20 - check values repetition and empty gaps
552///
553/// Third digit defines usage of typeinfo
554/// - kSkipTypeInfo = 100 - "_typename" field will be skipped, reading by ROOT or JSROOT may be impossible
555
557{
558 if (level < 0)
559 level = 0;
560 fCompact = level % 10;
561 if (fCompact >= kMapAsObject) {
564 }
565 fSemicolon = (fCompact >= kNoSpaces) ? ":" : " : ";
566 fArraySepar = (fCompact >= kNoSpaces) ? "," : ", ";
567 fArrayCompact = ((level / 10) % 10) * 10;
568 if ((((level / 100) % 10) * 100) == kSkipTypeInfo)
570 else if (fTypeNameTag.Length() == 0)
571 fTypeNameTag = "_typename";
572}
573
574////////////////////////////////////////////////////////////////////////////////
575/// Configures _typename tag in JSON structures
576/// By default "_typename" field in JSON structures used to store class information
577/// One can specify alternative tag like "$typename" or "xy", but such JSON can not be correctly used in JSROOT
578/// If empty string is provided, class information will not be stored
579
580void TBufferJSON::SetTypenameTag(const char *tag)
581{
582 if (!tag)
584 else
585 fTypeNameTag = tag;
586}
587
588////////////////////////////////////////////////////////////////////////////////
589/// Configures _typeversion tag in JSON
590/// One can specify name of the JSON tag like "_typeversion" or "$tv" which will be used to store class version
591/// Such tag can be used to correctly recover objects from JSON
592/// If empty string is provided (default), class version will not be stored
593
595{
596 if (!tag)
598 else
599 fTypeVersionTag = tag;
600}
601
602////////////////////////////////////////////////////////////////////////////////
603/// Specify class which typename will not be stored in JSON
604/// Several classes can be configured
605/// To exclude typeinfo for all classes, call TBufferJSON::SetTypenameTag("")
606
608{
609 if (!cl)
610 return;
611 if (!fSkipClasses)
612 fSkipClasses = new TObjArray();
613
614 fSkipClasses->Add(const_cast<TClass *>(cl));
615}
616
617////////////////////////////////////////////////////////////////////////////////
618/// Returns true if class info will be skipped from JSON
619
621{
622 if (!cl || !fSkipClasses) return kFALSE;
623
624 return fSkipClasses->FindObject(cl) != nullptr;
625}
626
627////////////////////////////////////////////////////////////////////////////////
628/// Converts any type of object to JSON string
629/// One should provide pointer on object and its class name
630/// Lower digit of compact parameter define formatting rules
631/// - 0 - no any compression, human-readable form
632/// - 1 - exclude spaces in the begin
633/// - 2 - remove newlines
634/// - 3 - exclude spaces as much as possible
635/// Second digit of compact parameter defines algorithm for arrays compression
636/// - 0 - no compression, standard JSON array
637/// - 1 - exclude leading and trailing zeros
638/// - 2 - check values repetition and empty gaps
639/// If third digit of compact parameter is 1, "_typename" will be skipped
640/// Maximal compression achieved when compact parameter equal to 23
641/// When member_name specified, converts only this data member
642
643TString TBufferJSON::ConvertToJSON(const void *obj, const TClass *cl, Int_t compact, const char *member_name)
644{
645 TClass *clActual = obj ? cl->GetActualClass(obj) : nullptr;
646 const void *actualStart = obj;
647 if (clActual && (clActual != cl)) {
648 actualStart = (char *)obj - clActual->GetBaseClassOffset(cl);
649 } else {
650 // We could not determine the real type of this object,
651 // let's assume it is the one given by the caller.
652 clActual = const_cast<TClass *>(cl);
653 }
654
655 if (member_name && actualStart) {
656 TRealData *rdata = clActual->GetRealData(member_name);
657 TDataMember *member = rdata ? rdata->GetDataMember() : nullptr;
658 if (!member) {
659 TIter iter(clActual->GetListOfRealData());
660 while ((rdata = dynamic_cast<TRealData *>(iter())) != nullptr) {
661 member = rdata->GetDataMember();
662 if (member && strcmp(member->GetName(), member_name) == 0)
663 break;
664 }
665 }
666 if (!member)
667 return TString();
668
669 Int_t arraylen = -1;
670 if (member->GetArrayIndex() != 0) {
671 TRealData *idata = clActual->GetRealData(member->GetArrayIndex());
672 TDataMember *imember = idata ? idata->GetDataMember() : nullptr;
673 if (imember && (strcmp(imember->GetTrueTypeName(), "int") == 0)) {
674 arraylen = *((int *)((char *)actualStart + idata->GetThisOffset()));
675 }
676 }
677
678 void *ptr = (char *)actualStart + rdata->GetThisOffset();
679 if (member->IsaPointer())
680 ptr = *((char **)ptr);
681
682 return TBufferJSON::ConvertToJSON(ptr, member, compact, arraylen);
683 }
684
685 TBufferJSON buf;
686
687 buf.SetCompact(compact);
688
689 buf.InitMap();
690
691 buf.PushStack(0); // dummy stack entry to avoid extra checks in the beginning
692
693 buf.JsonWriteObject(actualStart, clActual);
694
695 buf.PopStack();
696
697 return buf.fOutBuffer.Length() ? buf.fOutBuffer : buf.fValue;
698}
699
700////////////////////////////////////////////////////////////////////////////////
701/// Converts selected data member into json
702/// Parameter ptr specifies address in memory, where data member is located
703/// compact parameter defines compactness of produced JSON (from 0 to 3)
704/// arraylen (when specified) is array length for this data member, //[fN] case
705
706TString TBufferJSON::ConvertToJSON(const void *ptr, TDataMember *member, Int_t compact, Int_t arraylen)
707{
708 if (!ptr || !member)
709 return TString("null");
710
711 Bool_t stlstring = !strcmp(member->GetTrueTypeName(), "string");
712
713 Int_t isstl = member->IsSTLContainer();
714
715 TClass *mcl = member->IsBasic() ? nullptr : gROOT->GetClass(member->GetTypeName());
716
717 if (mcl && (mcl != TString::Class()) && !stlstring && !isstl && (mcl->GetBaseClassOffset(TArray::Class()) != 0) &&
718 (arraylen <= 0) && (member->GetArrayDim() == 0))
719 return TBufferJSON::ConvertToJSON(ptr, mcl, compact);
720
721 TBufferJSON buf;
722
723 buf.SetCompact(compact);
724
725 return buf.JsonWriteMember(ptr, member, mcl, arraylen);
726}
727
728////////////////////////////////////////////////////////////////////////////////
729/// Convert object into JSON and store in text file
730/// Returns size of the produce file
731/// Used in TObject::SaveAs()
732
733Int_t TBufferJSON::ExportToFile(const char *filename, const TObject *obj, const char *option)
734{
735 if (!obj || !filename || (*filename == 0))
736 return 0;
737
738 Int_t compact = strstr(filename, ".json.gz") ? 3 : 0;
739 if (option && (*option >= '0') && (*option <= '3'))
740 compact = TString(option).Atoi();
741
742 TString json = TBufferJSON::ConvertToJSON(obj, compact);
743
744 std::ofstream ofs(filename);
745
746 if (strstr(filename, ".json.gz")) {
747 const char *objbuf = json.Data();
748 Long_t objlen = json.Length();
749
750 unsigned long objcrc = R__crc32(0, NULL, 0);
751 objcrc = R__crc32(objcrc, (const unsigned char *)objbuf, objlen);
752
753 // 10 bytes (ZIP header), compressed data, 8 bytes (CRC and original length)
754 Int_t buflen = 10 + objlen + 8;
755 if (buflen < 512)
756 buflen = 512;
757
758 char *buffer = (char *)malloc(buflen);
759 if (!buffer)
760 return 0; // failure
761
762 char *bufcur = buffer;
763
764 *bufcur++ = 0x1f; // first byte of ZIP identifier
765 *bufcur++ = 0x8b; // second byte of ZIP identifier
766 *bufcur++ = 0x08; // compression method
767 *bufcur++ = 0x00; // FLAG - empty, no any file names
768 *bufcur++ = 0; // empty timestamp
769 *bufcur++ = 0; //
770 *bufcur++ = 0; //
771 *bufcur++ = 0; //
772 *bufcur++ = 0; // XFL (eXtra FLags)
773 *bufcur++ = 3; // OS 3 means Unix
774 // strcpy(bufcur, "item.json");
775 // bufcur += strlen("item.json")+1;
776
777 char dummy[8];
778 memcpy(dummy, bufcur - 6, 6);
779
780 // R__memcompress fills first 6 bytes with own header, therefore just overwrite them
781 unsigned long ziplen = R__memcompress(bufcur - 6, objlen + 6, (char *)objbuf, objlen);
782
783 memcpy(bufcur - 6, dummy, 6);
784
785 bufcur += (ziplen - 6); // jump over compressed data (6 byte is extra ROOT header)
786
787 *bufcur++ = objcrc & 0xff; // CRC32
788 *bufcur++ = (objcrc >> 8) & 0xff;
789 *bufcur++ = (objcrc >> 16) & 0xff;
790 *bufcur++ = (objcrc >> 24) & 0xff;
791
792 *bufcur++ = objlen & 0xff; // original data length
793 *bufcur++ = (objlen >> 8) & 0xff; // original data length
794 *bufcur++ = (objlen >> 16) & 0xff; // original data length
795 *bufcur++ = (objlen >> 24) & 0xff; // original data length
796
797 ofs.write(buffer, bufcur - buffer);
798
799 free(buffer);
800 } else {
801 ofs << json.Data();
802 }
803
804 ofs.close();
805
806 return json.Length();
807}
808
809////////////////////////////////////////////////////////////////////////////////
810/// Convert object into JSON and store in text file
811/// Returns size of the produce file
812
813Int_t TBufferJSON::ExportToFile(const char *filename, const void *obj, const TClass *cl, const char *option)
814{
815 if (!obj || !cl || !filename || (*filename == 0))
816 return 0;
817
818 Int_t compact = strstr(filename, ".json.gz") ? 3 : 0;
819 if (option && (*option >= '0') && (*option <= '3'))
820 compact = TString(option).Atoi();
821
822 TString json = TBufferJSON::ConvertToJSON(obj, cl, compact);
823
824 std::ofstream ofs(filename);
825
826 if (strstr(filename, ".json.gz")) {
827 const char *objbuf = json.Data();
828 Long_t objlen = json.Length();
829
830 unsigned long objcrc = R__crc32(0, NULL, 0);
831 objcrc = R__crc32(objcrc, (const unsigned char *)objbuf, objlen);
832
833 // 10 bytes (ZIP header), compressed data, 8 bytes (CRC and original length)
834 Int_t buflen = 10 + objlen + 8;
835 if (buflen < 512)
836 buflen = 512;
837
838 char *buffer = (char *)malloc(buflen);
839 if (!buffer)
840 return 0; // failure
841
842 char *bufcur = buffer;
843
844 *bufcur++ = 0x1f; // first byte of ZIP identifier
845 *bufcur++ = 0x8b; // second byte of ZIP identifier
846 *bufcur++ = 0x08; // compression method
847 *bufcur++ = 0x00; // FLAG - empty, no any file names
848 *bufcur++ = 0; // empty timestamp
849 *bufcur++ = 0; //
850 *bufcur++ = 0; //
851 *bufcur++ = 0; //
852 *bufcur++ = 0; // XFL (eXtra FLags)
853 *bufcur++ = 3; // OS 3 means Unix
854 // strcpy(bufcur, "item.json");
855 // bufcur += strlen("item.json")+1;
856
857 char dummy[8];
858 memcpy(dummy, bufcur - 6, 6);
859
860 // R__memcompress fills first 6 bytes with own header, therefore just overwrite them
861 unsigned long ziplen = R__memcompress(bufcur - 6, objlen + 6, (char *)objbuf, objlen);
862
863 memcpy(bufcur - 6, dummy, 6);
864
865 bufcur += (ziplen - 6); // jump over compressed data (6 byte is extra ROOT header)
866
867 *bufcur++ = objcrc & 0xff; // CRC32
868 *bufcur++ = (objcrc >> 8) & 0xff;
869 *bufcur++ = (objcrc >> 16) & 0xff;
870 *bufcur++ = (objcrc >> 24) & 0xff;
871
872 *bufcur++ = objlen & 0xff; // original data length
873 *bufcur++ = (objlen >> 8) & 0xff; // original data length
874 *bufcur++ = (objlen >> 16) & 0xff; // original data length
875 *bufcur++ = (objlen >> 24) & 0xff; // original data length
876
877 ofs.write(buffer, bufcur - buffer);
878
879 free(buffer);
880 } else {
881 ofs << json.Data();
882 }
883
884 ofs.close();
885
886 return json.Length();
887}
888
889////////////////////////////////////////////////////////////////////////////////
890/// Read TObject-based class from JSON, produced by ConvertToJSON() method.
891/// If object does not inherit from TObject class, return 0.
892
894{
895 TClass *cl = nullptr;
896 void *obj = ConvertFromJSONAny(str, &cl);
897
898 if (!cl || !obj)
899 return nullptr;
900
902
903 if (delta < 0) {
904 cl->Destructor(obj);
905 return nullptr;
906 }
907
908 return (TObject *)(((char *)obj) + delta);
909}
910
911////////////////////////////////////////////////////////////////////////////////
912/// Read object from JSON, produced by ConvertToJSON() method.
913/// In class pointer (if specified) read class is returned
914/// One must specify expected object class, if it is TArray or STL container
915
916void *TBufferJSON::ConvertFromJSONAny(const char *str, TClass **cl)
917{
918 TClass *objClass = nullptr;
919
920 if (cl) {
921 objClass = *cl; // this is class which suppose to created when reading JSON
922 *cl = nullptr;
923 }
924
925 nlohmann::json docu = nlohmann::json::parse(str);
926
927 if (docu.is_null() || (!docu.is_object() && !docu.is_array()))
928 return nullptr;
929
931
932 buf.InitMap();
933
934 buf.PushStack(0, &docu);
935
936 void *obj = buf.JsonReadObject(nullptr, objClass, cl);
937
938 buf.PopStack();
939
940 return obj;
941}
942
943////////////////////////////////////////////////////////////////////////////////
944/// Read objects from JSON, one can reuse existing object
945
946void *TBufferJSON::ConvertFromJSONChecked(const char *str, const TClass *expectedClass)
947{
948 if (!expectedClass)
949 return nullptr;
950
951 TClass *resClass = const_cast<TClass *>(expectedClass);
952
953 void *res = ConvertFromJSONAny(str, &resClass);
954
955 if (!res || !resClass)
956 return nullptr;
957
958 if (resClass == expectedClass)
959 return res;
960
961 Int_t offset = resClass->GetBaseClassOffset(expectedClass);
962 if (offset < 0) {
963 ::Error("TBufferJSON::ConvertFromJSONChecked", "expected class %s is not base for read class %s",
964 expectedClass->GetName(), resClass->GetName());
965 resClass->Destructor(res);
966 return nullptr;
967 }
968
969 return (char *)res - offset;
970}
971
972////////////////////////////////////////////////////////////////////////////////
973/// Convert single data member to JSON structures
974/// Returns string with converted member
975
976TString TBufferJSON::JsonWriteMember(const void *ptr, TDataMember *member, TClass *memberClass, Int_t arraylen)
977{
978 if (!member)
979 return "null";
980
981 if (gDebug > 2)
982 Info("JsonWriteMember", "Write member %s type %s ndim %d", member->GetName(), member->GetTrueTypeName(),
983 member->GetArrayDim());
984
985 Int_t tid = member->GetDataType() ? member->GetDataType()->GetType() : kNoType_t;
986 if (strcmp(member->GetTrueTypeName(), "const char*") == 0)
987 tid = kCharStar;
988 else if (!member->IsBasic() || (tid == kOther_t) || (tid == kVoid_t))
989 tid = kNoType_t;
990
991 if (!ptr)
992 return (tid == kCharStar) ? "\"\"" : "null";
993
994 PushStack(0);
995 fValue.Clear();
996
997 if (tid != kNoType_t) {
998
999 TArrayIndexProducer indx(member, arraylen, fArraySepar.Data());
1000
1001 Int_t shift = 1;
1002
1003 if (indx.IsArray() && (tid == kChar_t))
1004 shift = indx.ReduceDimension();
1005
1006 char *ppp = (char *)ptr;
1007
1008 if (indx.IsArray())
1009 fOutBuffer.Append(indx.GetBegin());
1010
1011 do {
1012 fValue.Clear();
1013
1014 switch (tid) {
1015 case kChar_t:
1016 if (shift > 1)
1017 JsonWriteConstChar((Char_t *)ppp, shift);
1018 else
1019 JsonWriteBasic(*((Char_t *)ppp));
1020 break;
1021 case kShort_t: JsonWriteBasic(*((Short_t *)ppp)); break;
1022 case kInt_t: JsonWriteBasic(*((Int_t *)ppp)); break;
1023 case kLong_t: JsonWriteBasic(*((Long_t *)ppp)); break;
1024 case kFloat_t: JsonWriteBasic(*((Float_t *)ppp)); break;
1025 case kCounter: JsonWriteBasic(*((Int_t *)ppp)); break;
1026 case kCharStar: JsonWriteConstChar((Char_t *)ppp); break;
1027 case kDouble_t: JsonWriteBasic(*((Double_t *)ppp)); break;
1028 case kDouble32_t: JsonWriteBasic(*((Double_t *)ppp)); break;
1029 case kchar: JsonWriteBasic(*((char *)ppp)); break;
1030 case kUChar_t: JsonWriteBasic(*((UChar_t *)ppp)); break;
1031 case kUShort_t: JsonWriteBasic(*((UShort_t *)ppp)); break;
1032 case kUInt_t: JsonWriteBasic(*((UInt_t *)ppp)); break;
1033 case kULong_t: JsonWriteBasic(*((ULong_t *)ppp)); break;
1034 case kBits: JsonWriteBasic(*((UInt_t *)ppp)); break;
1035 case kLong64_t: JsonWriteBasic(*((Long64_t *)ppp)); break;
1036 case kULong64_t: JsonWriteBasic(*((ULong64_t *)ppp)); break;
1037 case kBool_t: JsonWriteBasic(*((Bool_t *)ppp)); break;
1038 case kFloat16_t: JsonWriteBasic(*((Float_t *)ppp)); break;
1039 case kOther_t:
1040 case kVoid_t: break;
1041 }
1042
1044 if (indx.IsArray())
1045 fOutBuffer.Append(indx.NextSeparator());
1046
1047 ppp += shift * member->GetUnitSize();
1048
1049 } while (!indx.IsDone());
1050
1052
1053 } else if (memberClass == TString::Class()) {
1054 TString *str = (TString *)ptr;
1055 JsonWriteConstChar(str ? str->Data() : nullptr);
1056 } else if ((member->IsSTLContainer() == ROOT::kSTLvector) || (member->IsSTLContainer() == ROOT::kSTLlist) ||
1057 (member->IsSTLContainer() == ROOT::kSTLforwardlist)) {
1058
1059 if (memberClass)
1060 memberClass->Streamer((void *)ptr, *this);
1061 else
1062 fValue = "[]";
1063
1064 if (fValue == "0")
1065 fValue = "[]";
1066
1067 } else if (memberClass && memberClass->GetBaseClassOffset(TArray::Class()) == 0) {
1068 TArray *arr = (TArray *)ptr;
1069 if (arr && (arr->GetSize() > 0)) {
1070 arr->Streamer(*this);
1071 // WriteFastArray(arr->GetArray(), arr->GetSize());
1072 if (Stack()->fValues.size() > 1) {
1073 Warning("TBufferJSON", "When streaming TArray, more than 1 object in the stack, use second item");
1074 fValue = Stack()->fValues[1].c_str();
1075 }
1076 } else
1077 fValue = "[]";
1078 } else if (memberClass && !strcmp(memberClass->GetName(), "string")) {
1079 // here value contains quotes, stack can be ignored
1080 memberClass->Streamer((void *)ptr, *this);
1081 }
1082 PopStack();
1083
1084 if (fValue.Length())
1085 return fValue;
1086
1087 if (!memberClass || (member->GetArrayDim() > 0) || (arraylen > 0))
1088 return "<not supported>";
1089
1090 return TBufferJSON::ConvertToJSON(ptr, memberClass);
1091}
1092
1093////////////////////////////////////////////////////////////////////////////////
1094/// add new level to the structures stack
1095
1096TJSONStackObj *TBufferJSON::PushStack(Int_t inclevel, void *readnode)
1097{
1098 auto next = new TJSONStackObj();
1099 next->fLevel = inclevel;
1100 if (IsReading()) {
1101 next->fNode = (nlohmann::json *)readnode;
1102 } else if (fStack.size() > 0) {
1103 auto prev = Stack();
1104 next->fLevel += prev->fLevel;
1105 next->fMemberPtr = prev->fMemberPtr;
1106 }
1107 fStack.push_back(next);
1108 return next;
1109}
1110
1111////////////////////////////////////////////////////////////////////////////////
1112/// remove one level from stack
1113
1115{
1116 if (fStack.size() > 0) {
1117 delete fStack.back();
1118 fStack.pop_back();
1119 }
1120
1121 return fStack.size() > 0 ? Stack() : nullptr;
1122}
1123
1124////////////////////////////////////////////////////////////////////////////////
1125/// Append two string to the output JSON, normally separate by line break
1126
1127void TBufferJSON::AppendOutput(const char *line0, const char *line1)
1128{
1129 if (line0)
1130 fOutput->Append(line0);
1131
1132 if (line1) {
1133 if (fCompact < 2)
1134 fOutput->Append("\n");
1135
1136 if (strlen(line1) > 0) {
1137 if (fCompact < 1) {
1138 if (Stack()->fLevel > 0)
1139 fOutput->Append(' ', Stack()->fLevel);
1140 }
1141 fOutput->Append(line1);
1142 }
1143 }
1144}
1145
1146////////////////////////////////////////////////////////////////////////////////
1147/// Start object element with typeinfo
1148
1149TJSONStackObj *TBufferJSON::JsonStartObjectWrite(const TClass *obj_class, TStreamerInfo *info)
1150{
1151 auto stack = PushStack(2);
1152
1153 // new object started - assign own member counter
1154 stack->fMemberPtr = &stack->fMemberCnt;
1155
1156 if ((fTypeNameTag.Length() > 0) && !IsSkipClassInfo(obj_class)) {
1157 // stack->fMemberCnt = 1; // default value, comment out here
1158 AppendOutput("{", "\"");
1160 AppendOutput("\"");
1162 AppendOutput("\"");
1163 AppendOutput(obj_class->GetName());
1164 AppendOutput("\"");
1165 if (fTypeVersionTag.Length() > 0) {
1166 AppendOutput(stack->NextMemberSeparator(), "\"");
1168 AppendOutput("\"");
1170 AppendOutput(Form("%d", (int)(info ? info->GetClassVersion() : obj_class->GetClassVersion())));
1171 }
1172 } else {
1173 stack->fMemberCnt = 0; // exclude typename
1174 AppendOutput("{");
1175 }
1176
1177 return stack;
1178}
1179
1180////////////////////////////////////////////////////////////////////////////////
1181/// Start new class member in JSON structures
1182
1183void TBufferJSON::JsonStartElement(const TStreamerElement *elem, const TClass *base_class)
1184{
1185 const char *elem_name = nullptr;
1186 Int_t special_kind = JsonSpecialClass(base_class);
1187
1188 switch (special_kind) {
1189 case 0:
1190 if (!base_class)
1191 elem_name = elem->GetName();
1192 break;
1193 case TClassEdit::kVector: elem_name = "fVector"; break;
1194 case TClassEdit::kList: elem_name = "fList"; break;
1195 case TClassEdit::kForwardlist: elem_name = "fForwardlist"; break;
1196 case TClassEdit::kDeque: elem_name = "fDeque"; break;
1197 case TClassEdit::kMap: elem_name = "fMap"; break;
1198 case TClassEdit::kMultiMap: elem_name = "fMultiMap"; break;
1199 case TClassEdit::kSet: elem_name = "fSet"; break;
1200 case TClassEdit::kMultiSet: elem_name = "fMultiSet"; break;
1201 case TClassEdit::kUnorderedSet: elem_name = "fUnorderedSet"; break;
1202 case TClassEdit::kUnorderedMultiSet: elem_name = "fUnorderedMultiSet"; break;
1203 case TClassEdit::kUnorderedMap: elem_name = "fUnorderedMap"; break;
1204 case TClassEdit::kUnorderedMultiMap: elem_name = "fUnorderedMultiMap"; break;
1205 case TClassEdit::kBitSet: elem_name = "fBitSet"; break;
1206 case json_TArray: elem_name = "fArray"; break;
1207 case json_TString:
1208 case json_stdstring: elem_name = "fString"; break;
1209 }
1210
1211 if (!elem_name)
1212 return;
1213
1214 if (IsReading()) {
1215 nlohmann::json *json = Stack()->fNode;
1216
1217 if (json->count(elem_name) != 1) {
1218 Error("JsonStartElement", "Missing JSON structure for element %s", elem_name);
1219 } else {
1220 Stack()->fNode = &((*json)[elem_name]);
1221 if (special_kind == json_TArray) {
1222 Int_t len = Stack()->IsJsonArray();
1223 Stack()->PushIntValue(len > 0 ? len : 0);
1224 if (len < 0)
1225 Error("JsonStartElement", "Missing array when reading TArray class for element %s", elem->GetName());
1226 }
1227 if ((gDebug > 1) && base_class)
1228 Info("JsonStartElement", "Reading baseclass %s from element %s", base_class->GetName(), elem_name);
1229 }
1230
1231 } else {
1232 AppendOutput(Stack()->NextMemberSeparator(), "\"");
1233 AppendOutput(elem_name);
1234 AppendOutput("\"");
1236 }
1237}
1238
1239////////////////////////////////////////////////////////////////////////////////
1240/// disable post-processing of the code
1242{
1243 Stack()->fIsPostProcessed = kTRUE;
1244}
1245
1246////////////////////////////////////////////////////////////////////////////////
1247/// return non-zero value when class has special handling in JSON
1248/// it is TCollection (-130), TArray (100), TString (110), std::string (120) and STL containers (1..6)
1249
1251{
1252 if (!cl)
1253 return 0;
1254
1255 Bool_t isarray = strncmp("TArray", cl->GetName(), 6) == 0;
1256 if (isarray)
1257 isarray = (const_cast<TClass *>(cl))->GetBaseClassOffset(TArray::Class()) == 0;
1258 if (isarray)
1259 return json_TArray;
1260
1261 // negative value used to indicate that collection stored as object
1262 if ((const_cast<TClass *>(cl))->GetBaseClassOffset(TCollection::Class()) == 0)
1263 return json_TCollection;
1264
1265 // special case for TString - it is saved as string in JSON
1266 if (cl == TString::Class())
1267 return json_TString;
1268
1269 bool isstd = TClassEdit::IsStdClass(cl->GetName());
1270 int isstlcont(ROOT::kNotSTL);
1271 if (isstd)
1272 isstlcont = cl->GetCollectionType();
1273 if (isstlcont > 0)
1274 return isstlcont;
1275
1276 // also special handling for STL string, which handled similar to TString
1277 if (isstd && !strcmp(cl->GetName(), "string"))
1278 return json_stdstring;
1279
1280 return 0;
1281}
1282
1283////////////////////////////////////////////////////////////////////////////////
1284/// Write object to buffer
1285/// If object was written before, only pointer will be stored
1286/// If check_map==kFALSE, object will be stored in any case and pointer will not be registered in the map
1287
1288void TBufferJSON::JsonWriteObject(const void *obj, const TClass *cl, Bool_t check_map)
1289{
1290 if (!cl)
1291 obj = nullptr;
1292
1293 if (gDebug > 0)
1294 Info("JsonWriteObject", "Object %p class %s check_map %s", obj, cl ? cl->GetName() : "null",
1295 check_map ? "true" : "false");
1296
1297 Int_t special_kind = JsonSpecialClass(cl), map_convert{0};
1298
1299 TString fObjectOutput, *fPrevOutput{nullptr};
1300
1301 TJSONStackObj *stack = Stack();
1302
1303 if (stack && stack->fAccObjects && ((fValue.Length() > 0) || (stack->fValues.size() > 0))) {
1304 // accumulate data of super-object in stack
1305
1306 if (fValue.Length() > 0)
1307 stack->PushValue(fValue);
1308
1309 // redirect output to local buffer, use it later as value
1310 fPrevOutput = fOutput;
1311 fOutput = &fObjectOutput;
1312 } else if ((special_kind <= 0) || (special_kind > json_TArray)) {
1313 // FIXME: later post processing should be active for all special classes, while they all keep output in the value
1315 } else if ((special_kind == TClassEdit::kMap) || (special_kind == TClassEdit::kMultiMap) ||
1316 (special_kind == TClassEdit::kUnorderedMap) || (special_kind == TClassEdit::kUnorderedMultiMap)) {
1317
1318 if ((fMapAsObject && (fStack.size()==1)) || (stack && stack->fElem && strstr(stack->fElem->GetTitle(), "JSON_object")))
1319 map_convert = 2; // mapped into normal object
1320 else
1321 map_convert = 1;
1322 }
1323
1324 if (!obj) {
1325 AppendOutput("null");
1326 goto post_process;
1327 }
1328
1329 if (special_kind <= 0) {
1330 // add element name which should correspond to the object
1331 if (check_map) {
1332 Long64_t refid = GetObjectTag(obj);
1333 if (refid > 0) {
1334 // old-style refs, coded into string like "$ref12"
1335 // AppendOutput(Form("\"$ref:%u\"", iter->second));
1336 // new-style refs, coded into extra object {"$ref":12}, auto-detected by JSROOT 4.8 and higher
1337 AppendOutput(Form("{\"$ref\":%u}", (unsigned)(refid - 1)));
1338 goto post_process;
1339 }
1340 MapObject(obj, cl, fJsonrCnt + 1); // +1 used
1341 }
1342
1343 fJsonrCnt++; // object counts required in dereferencing part
1344
1345 stack = JsonStartObjectWrite(cl);
1346
1347 } else if (map_convert == 2) {
1348 // special handling of map - it is object, but stored in the fValue
1349
1350 if (check_map) {
1351 Long64_t refid = GetObjectTag(obj);
1352 if (refid > 0) {
1353 fValue.Form("{\"$ref\":%u}", (unsigned)(refid - 1));
1354 goto post_process;
1355 }
1356 MapObject(obj, cl, fJsonrCnt + 1); // +1 used
1357 }
1358
1359 fJsonrCnt++; // object counts required in dereferencing part
1360 stack = PushStack(0);
1361
1362 } else {
1363 // for array, string and STL collections different handling -
1364 // they not recognized at the end as objects in JSON
1365 stack = PushStack(0);
1366 }
1367
1368 if (gDebug > 3)
1369 Info("JsonWriteObject", "Starting object %p write for class: %s", obj, cl->GetName());
1370
1371 stack->fAccObjects = special_kind < ROOT::kSTLend;
1372
1373 if (special_kind == json_TCollection)
1374 JsonWriteCollection((TCollection *)obj, cl);
1375 else
1376 (const_cast<TClass *>(cl))->Streamer((void *)obj, *this);
1377
1378 if (gDebug > 3)
1379 Info("JsonWriteObject", "Done object %p write for class: %s", obj, cl->GetName());
1380
1381 if (special_kind == json_TArray) {
1382 if (stack->fValues.size() != 1)
1383 Error("JsonWriteObject", "Problem when writing array");
1384 stack->fValues.clear();
1385 } else if ((special_kind == json_TString) || (special_kind == json_stdstring)) {
1386 if (stack->fValues.size() > 2)
1387 Error("JsonWriteObject", "Problem when writing TString or std::string");
1388 stack->fValues.clear();
1390 fValue.Clear();
1391 } else if ((special_kind > 0) && (special_kind < ROOT::kSTLend)) {
1392 // here make STL container processing
1393
1394 if (stack->fValues.empty()) {
1395 // empty container
1396 if (fValue != "0")
1397 Error("JsonWriteObject", "With empty stack fValue!=0");
1398 fValue = "[]";
1399 } else {
1400
1401 auto size = std::stoi(stack->fValues[0]);
1402
1403 bool trivial_format = false;
1404
1405 if ((stack->fValues.size() == 1) && ((size > 1) || ((fValue.Length() > 1) && (fValue[0]=='[')))) {
1406 // prevent case of vector<vector<value_class>>
1407 const auto proxy = cl->GetCollectionProxy();
1408 TClass *value_class = proxy ? proxy->GetValueClass() : nullptr;
1409 if (value_class && TClassEdit::IsStdClass(value_class->GetName()) && (value_class->GetCollectionType() != ROOT::kNotSTL))
1410 trivial_format = false;
1411 else
1412 trivial_format = true;
1413 }
1414
1415 if (trivial_format) {
1416 // case of simple vector, array already in the value
1417 stack->fValues.clear();
1418 if (fValue.Length() == 0) {
1419 Error("JsonWriteObject", "Empty value when it should contain something");
1420 fValue = "[]";
1421 }
1422
1423 } else if (map_convert == 2) {
1424 // converting map into object
1425 if (fValue.Length() > 0)
1426 stack->PushValue(fValue);
1427
1428 const char *separ = (fCompact < 2) ? ", " : ",";
1429 const char *semi = (fCompact < 2) ? ": " : ":";
1430 bool first = true;
1431
1432 fValue = "{";
1433 if (fTypeNameTag.Length() > 0) {
1434 fValue.Append("\"");
1436 fValue.Append("\"");
1437 fValue.Append(semi);
1438 fValue.Append("\"");
1439 fValue.Append(cl->GetName());
1440 fValue.Append("\"");
1441 first = false;
1442 }
1443 for (Int_t k = 1; k < (int) stack->fValues.size() - 1; k += 2) {
1444 if (!first)
1445 fValue.Append(separ);
1446 first = false;
1447 fValue.Append(stack->fValues[k].c_str());
1448 fValue.Append(semi);
1449 fValue.Append(stack->fValues[k + 1].c_str());
1450 }
1451 fValue.Append("}");
1452 stack->fValues.clear();
1453 } else {
1454 const char *separ = "[";
1455
1456 if (fValue.Length() > 0)
1457 stack->PushValue(fValue);
1458
1459 if ((size * 2 == (int) stack->fValues.size() - 1) && (map_convert > 0)) {
1460 // special handling for std::map.
1461 // Create entries like { '$pair': 'typename' , 'first' : key, 'second' : value }
1462 TString pairtype = cl->GetName();
1463 if (pairtype.Index("unordered_map<") == 0)
1464 pairtype.Replace(0, 14, "pair<");
1465 else if (pairtype.Index("unordered_multimap<") == 0)
1466 pairtype.Replace(0, 19, "pair<");
1467 else if (pairtype.Index("multimap<") == 0)
1468 pairtype.Replace(0, 9, "pair<");
1469 else if (pairtype.Index("map<") == 0)
1470 pairtype.Replace(0, 4, "pair<");
1471 else
1472 pairtype = "TPair";
1473 if (fTypeNameTag.Length() == 0)
1474 pairtype = "1";
1475 else
1476 pairtype = TString("\"") + pairtype + TString("\"");
1477 for (Int_t k = 1; k < (int) stack->fValues.size() - 1; k += 2) {
1478 fValue.Append(separ);
1479 separ = fArraySepar.Data();
1480 // fJsonrCnt++; // do not add entry in the map, can conflict with objects inside values
1481 fValue.Append("{");
1482 fValue.Append("\"$pair\"");
1484 fValue.Append(pairtype.Data());
1486 fValue.Append("\"first\"");
1488 fValue.Append(stack->fValues[k].c_str());
1490 fValue.Append("\"second\"");
1492 fValue.Append(stack->fValues[k + 1].c_str());
1493 fValue.Append("}");
1494 }
1495 } else {
1496 // for most stl containers write just like blob, but skipping first element with size
1497 for (Int_t k = 1; k < (int) stack->fValues.size(); k++) {
1498 fValue.Append(separ);
1499 separ = fArraySepar.Data();
1500 fValue.Append(stack->fValues[k].c_str());
1501 }
1502 }
1503
1504 fValue.Append("]");
1505 stack->fValues.clear();
1506 }
1507 }
1508 }
1509
1510 // reuse post-processing code for TObject or TRef
1511 PerformPostProcessing(stack, cl);
1512
1513 if ((special_kind == 0) && (!stack->fValues.empty() || (fValue.Length() > 0))) {
1514 if (gDebug > 0)
1515 Info("JsonWriteObject", "Create blob value for class %s", cl->GetName());
1516
1517 AppendOutput(fArraySepar.Data(), "\"_blob\"");
1519
1520 const char *separ = "[";
1521
1522 for (auto &elem: stack->fValues) {
1523 AppendOutput(separ);
1524 separ = fArraySepar.Data();
1525 AppendOutput(elem.c_str());
1526 }
1527
1528 if (fValue.Length() > 0) {
1529 AppendOutput(separ);
1531 }
1532
1533 AppendOutput("]");
1534
1535 fValue.Clear();
1536 stack->fValues.clear();
1537 }
1538
1539 PopStack();
1540
1541 if ((special_kind <= 0))
1542 AppendOutput(nullptr, "}");
1543
1544post_process:
1545
1546 if (fPrevOutput) {
1547 fOutput = fPrevOutput;
1548 // for STL containers and TArray object in fValue itself
1549 if ((special_kind <= 0) || (special_kind > json_TArray))
1550 fValue = fObjectOutput;
1551 else if (fObjectOutput.Length() != 0)
1552 Error("JsonWriteObject", "Non-empty object output for special class %s", cl->GetName());
1553 }
1554}
1555
1556////////////////////////////////////////////////////////////////////////////////
1557/// store content of ROOT collection
1558
1560{
1561 AppendOutput(Stack()->NextMemberSeparator(), "\"name\"");
1563 AppendOutput("\"");
1564 AppendOutput(col->GetName());
1565 AppendOutput("\"");
1566 AppendOutput(Stack()->NextMemberSeparator(), "\"arr\"");
1568
1569 // collection treated as JS Array
1570 AppendOutput("[");
1571
1572 bool islist = col->InheritsFrom(TList::Class());
1573 TMap *map = nullptr;
1574 if (col->InheritsFrom(TMap::Class()))
1575 map = dynamic_cast<TMap *>(col);
1576
1577 TString sopt;
1578 if (islist) {
1579 sopt.Capacity(500);
1580 sopt = "[";
1581 }
1582
1583 TIter iter(col);
1584 TObject *obj;
1585 Bool_t first = kTRUE;
1586 while ((obj = iter()) != nullptr) {
1587 if (!first)
1589
1590 if (map) {
1591 // fJsonrCnt++; // do not account map pair as JSON object
1592 AppendOutput("{", "\"$pair\"");
1594 AppendOutput("\"TPair\"");
1595 AppendOutput(fArraySepar.Data(), "\"first\"");
1597 }
1598
1600
1601 if (map) {
1602 AppendOutput(fArraySepar.Data(), "\"second\"");
1605 AppendOutput("", "}");
1606 }
1607
1608 if (islist) {
1609 if (!first)
1610 sopt.Append(fArraySepar.Data());
1611 sopt.Append("\"");
1612 sopt.Append(iter.GetOption());
1613 sopt.Append("\"");
1614 }
1615
1616 first = kFALSE;
1617 }
1618
1619 AppendOutput("]");
1620
1621 if (islist) {
1622 sopt.Append("]");
1623 AppendOutput(Stack()->NextMemberSeparator(), "\"opt\"");
1625 AppendOutput(sopt.Data());
1626 }
1627 fValue.Clear();
1628}
1629
1630////////////////////////////////////////////////////////////////////////////////
1631/// read content of ROOT collection
1632
1634{
1635 if (!col)
1636 return;
1637
1638 TList *lst = nullptr;
1639 TMap *map = nullptr;
1640 TClonesArray *clones = nullptr;
1641 if (col->InheritsFrom(TList::Class()))
1642 lst = dynamic_cast<TList *>(col);
1643 else if (col->InheritsFrom(TMap::Class()))
1644 map = dynamic_cast<TMap *>(col);
1645 else if (col->InheritsFrom(TClonesArray::Class()))
1646 clones = dynamic_cast<TClonesArray *>(col);
1647
1648 nlohmann::json *json = Stack()->fNode;
1649
1650 std::string name = json->at("name");
1651 col->SetName(name.c_str());
1652
1653 nlohmann::json &arr = json->at("arr");
1654 int size = arr.size();
1655
1656 for (int n = 0; n < size; ++n) {
1657 nlohmann::json *subelem = &arr.at(n);
1658
1659 if (map)
1660 subelem = &subelem->at("first");
1661
1662 PushStack(0, subelem);
1663
1664 TClass *readClass = nullptr, *objClass = nullptr;
1665 void *subobj = nullptr;
1666
1667 if (clones) {
1668 if (n == 0) {
1669 if (!clones->GetClass() || (clones->GetSize() == 0)) {
1670 if (fTypeNameTag.Length() > 0) {
1671 clones->SetClass(subelem->at(fTypeNameTag.Data()).get<std::string>().c_str(), size);
1672 } else {
1673 Error("JsonReadCollection",
1674 "Cannot detect class name for TClonesArray - typename tag not configured");
1675 return;
1676 }
1677 } else if (size > clones->GetSize()) {
1678 Error("JsonReadCollection", "TClonesArray size %d smaller than required %d", clones->GetSize(), size);
1679 return;
1680 }
1681 }
1682 objClass = clones->GetClass();
1683 subobj = clones->ConstructedAt(n);
1684 }
1685
1686 subobj = JsonReadObject(subobj, objClass, &readClass);
1687
1688 PopStack();
1689
1690 if (clones)
1691 continue;
1692
1693 if (!subobj || !readClass) {
1694 subobj = nullptr;
1695 } else if (readClass->GetBaseClassOffset(TObject::Class()) != 0) {
1696 Error("JsonReadCollection", "Try to add object %s not derived from TObject", readClass->GetName());
1697 subobj = nullptr;
1698 }
1699
1700 TObject *tobj = static_cast<TObject *>(subobj);
1701
1702 if (map) {
1703 PushStack(0, &arr.at(n).at("second"));
1704
1705 readClass = nullptr;
1706 void *subobj2 = JsonReadObject(nullptr, nullptr, &readClass);
1707
1708 PopStack();
1709
1710 if (!subobj2 || !readClass) {
1711 subobj2 = nullptr;
1712 } else if (readClass->GetBaseClassOffset(TObject::Class()) != 0) {
1713 Error("JsonReadCollection", "Try to add object %s not derived from TObject", readClass->GetName());
1714 subobj2 = nullptr;
1715 }
1716
1717 map->Add(tobj, static_cast<TObject *>(subobj2));
1718 } else if (lst) {
1719 std::string opt = json->at("opt").at(n).get<std::string>();
1720 lst->Add(tobj, opt.c_str());
1721 } else {
1722 // generic method, all kinds of TCollection should work
1723 col->Add(tobj);
1724 }
1725 }
1726}
1727
1728////////////////////////////////////////////////////////////////////////////////
1729/// Read object from current JSON node
1730
1731void *TBufferJSON::JsonReadObject(void *obj, const TClass *objClass, TClass **readClass)
1732{
1733 if (readClass)
1734 *readClass = nullptr;
1735
1736 TJSONStackObj *stack = Stack();
1737
1738 Bool_t process_stl = stack->IsStl();
1739 nlohmann::json *json = stack->GetStlNode();
1740
1741 // check if null pointer
1742 if (json->is_null())
1743 return nullptr;
1744
1745 Int_t special_kind = JsonSpecialClass(objClass);
1746
1747 // Extract pointer
1748 if (json->is_object() && (json->size() == 1) && (json->find("$ref") != json->end())) {
1749 unsigned refid = json->at("$ref").get<unsigned>();
1750
1751 void *ref_obj = nullptr;
1752 TClass *ref_cl = nullptr;
1753
1754 GetMappedObject(refid + 1, ref_obj, ref_cl);
1755
1756 if (!ref_obj || !ref_cl) {
1757 Error("JsonReadObject", "Fail to find object for reference %u", refid);
1758 return nullptr;
1759 }
1760
1761 if (readClass)
1762 *readClass = ref_cl;
1763
1764 if (gDebug > 2)
1765 Info("JsonReadObject", "Extract object reference %u %p cl:%s expects:%s", refid, ref_obj, ref_cl->GetName(),
1766 (objClass ? objClass->GetName() : "---"));
1767
1768 return ref_obj;
1769 }
1770
1771 // special case of strings - they do not create JSON object, but just string
1772 if ((special_kind == json_stdstring) || (special_kind == json_TString)) {
1773 if (!obj)
1774 obj = objClass->New();
1775
1776 if (gDebug > 2)
1777 Info("JsonReadObject", "Read string from %s", json->dump().c_str());
1778
1779 if (special_kind == json_stdstring)
1780 *((std::string *)obj) = json->get<std::string>();
1781 else
1782 *((TString *)obj) = json->get<std::string>().c_str();
1783
1784 if (readClass)
1785 *readClass = const_cast<TClass *>(objClass);
1786
1787 return obj;
1788 }
1789
1790 Bool_t isBase = (stack->fElem && objClass) ? stack->fElem->IsBase() : kFALSE; // base class
1791
1792 if (isBase && (!obj || !objClass)) {
1793 Error("JsonReadObject", "No object when reading base class");
1794 return obj;
1795 }
1796
1797 Int_t map_convert = 0;
1798 if ((special_kind == TClassEdit::kMap) || (special_kind == TClassEdit::kMultiMap) ||
1799 (special_kind == TClassEdit::kUnorderedMap) || (special_kind == TClassEdit::kUnorderedMultiMap)) {
1800 map_convert = json->is_object() ? 2 : 1; // check if map was written as array or as object
1801 }
1802
1803 // from now all operations performed with sub-element,
1804 // stack should be repaired at the end
1805 if (process_stl)
1806 stack = PushStack(0, json);
1807
1808 TClass *jsonClass = nullptr;
1809 Int_t jsonClassVersion = 0;
1810
1811 if ((special_kind == json_TArray) || ((special_kind > 0) && (special_kind < ROOT::kSTLend))) {
1812
1813 jsonClass = const_cast<TClass *>(objClass);
1814
1815 if (!obj)
1816 obj = jsonClass->New();
1817
1818 Int_t len = stack->IsJsonArray(json, map_convert == 2 ? fTypeNameTag.Data() : nullptr);
1819
1820 stack->PushIntValue(len > 0 ? len : 0);
1821
1822 if (len < 0) // should never happens
1823 Error("JsonReadObject", "Not array when expecting such %s", json->dump().c_str());
1824
1825 if (gDebug > 1)
1826 Info("JsonReadObject", "Reading special kind %d %s ptr %p", special_kind, objClass->GetName(), obj);
1827
1828 } else if (isBase) {
1829 // base class has special handling - no additional level and no extra refid
1830
1831 jsonClass = const_cast<TClass *>(objClass);
1832
1833 if (gDebug > 1)
1834 Info("JsonReadObject", "Reading baseclass %s ptr %p", objClass->GetName(), obj);
1835 } else {
1836
1837 if ((fTypeNameTag.Length() > 0) && (json->count(fTypeNameTag.Data()) > 0)) {
1838 std::string clname = json->at(fTypeNameTag.Data()).get<std::string>();
1839 jsonClass = TClass::GetClass(clname.c_str());
1840 if (!jsonClass)
1841 Error("JsonReadObject", "Cannot find class %s", clname.c_str());
1842 } else {
1843 // try to use class which is assigned by streamers - better than nothing
1844 jsonClass = const_cast<TClass *>(objClass);
1845 }
1846
1847 if (!jsonClass) {
1848 if (process_stl)
1849 PopStack();
1850 return obj;
1851 }
1852
1853 if ((fTypeVersionTag.Length() > 0) && (json->count(fTypeVersionTag.Data()) > 0))
1854 jsonClassVersion = json->at(fTypeVersionTag.Data()).get<int>();
1855
1856 if (objClass && (jsonClass != objClass)) {
1857 Error("JsonReadObject", "Class mismatch between provided %s and in JSON %s", objClass->GetName(),
1858 jsonClass->GetName());
1859 }
1860
1861 if (!obj)
1862 obj = jsonClass->New();
1863
1864 if (gDebug > 1)
1865 Info("JsonReadObject", "Reading object of class %s refid %u ptr %p", jsonClass->GetName(), fJsonrCnt, obj);
1866
1867 if (!special_kind)
1868 special_kind = JsonSpecialClass(jsonClass);
1869
1870 // add new element to the reading map
1871 MapObject(obj, jsonClass, ++fJsonrCnt);
1872 }
1873
1874 // there are two ways to handle custom streamers
1875 // either prepare data before streamer and tweak basic function which are reading values like UInt32_t
1876 // or try re-implement custom streamer here
1877
1878 if ((jsonClass == TObject::Class()) || (jsonClass == TRef::Class())) {
1879 // for TObject we re-implement custom streamer - it is much easier
1880
1881 JsonReadTObjectMembers((TObject *)obj, json);
1882
1883 } else if (special_kind == json_TCollection) {
1884
1885 JsonReadCollection((TCollection *)obj, jsonClass);
1886
1887 } else {
1888
1889 Bool_t do_read = kTRUE;
1890
1891 // special handling of STL which coded into arrays
1892 if ((special_kind > 0) && (special_kind < ROOT::kSTLend))
1893 do_read = stack->AssignStl(jsonClass, map_convert, fTypeNameTag.Data());
1894
1895 // if provided - use class version from JSON
1896 stack->fClVersion = jsonClassVersion ? jsonClassVersion : jsonClass->GetClassVersion();
1897
1898 if (gDebug > 3)
1899 Info("JsonReadObject", "Calling streamer of class %s", jsonClass->GetName());
1900
1901 if (isBase && (special_kind == 0))
1902 Error("JsonReadObject", "Should not be used for reading of base class %s", jsonClass->GetName());
1903
1904 if (do_read)
1905 jsonClass->Streamer((void *)obj, *this);
1906
1907 stack->fClVersion = 0;
1908
1909 stack->ClearStl(); // reset STL index for itself to prevent looping
1910 }
1911
1912 // return back stack position
1913 if (process_stl)
1914 PopStack();
1915
1916 if (gDebug > 1)
1917 Info("JsonReadObject", "Reading object of class %s done", jsonClass->GetName());
1918
1919 if (readClass)
1920 *readClass = jsonClass;
1921
1922 return obj;
1923}
1924
1926{
1927 nlohmann::json *json = node ? (nlohmann::json *)node : Stack()->fNode;
1928
1929 UInt_t uid = json->at("fUniqueID").get<unsigned>();
1930 UInt_t bits = json->at("fBits").get<unsigned>();
1931 // UInt32_t pid = json->at("fPID").get<unsigned>(); // ignore PID for the moment
1932
1933 tobj->SetUniqueID(uid);
1934 // there is no method to set all bits directly - do it one by one
1935 for (unsigned n = 0; n < 32; n++)
1936 tobj->SetBit(BIT(n), (bits & BIT(n)) != 0);
1937
1938 if (gDebug > 2)
1939 Info("JsonReadTObjectMembers", "Reading TObject part bits %u kMustCleanup %d", bits, tobj->TestBit(kMustCleanup));
1940}
1941
1942////////////////////////////////////////////////////////////////////////////////
1943/// Function is called from TStreamerInfo WriteBuffer and ReadBuffer functions
1944/// and indent new level in json structure.
1945/// This call indicates, that TStreamerInfo functions starts streaming
1946/// object data of correspondent class
1947
1949{
1950 if (gDebug > 2)
1951 Info("IncrementLevel", "Class: %s", (info ? info->GetClass()->GetName() : "custom"));
1952
1954}
1955
1956////////////////////////////////////////////////////////////////////////////////
1957/// Prepares buffer to stream data of specified class
1958
1960{
1961 if (sinfo)
1962 cl = sinfo->GetClass();
1963
1964 if (!cl)
1965 return;
1966
1967 if (gDebug > 3)
1968 Info("WorkWithClass", "Class: %s", cl->GetName());
1969
1970 TJSONStackObj *stack = Stack();
1971
1972 if (IsReading()) {
1973 stack = PushStack(0, stack->fNode);
1974 } else if (stack && stack->IsStreamerElement() && !stack->fIsObjStarted &&
1975 ((stack->fElem->GetType() == TStreamerInfo::kObject) ||
1976 (stack->fElem->GetType() == TStreamerInfo::kAny))) {
1977
1978 stack->fIsObjStarted = kTRUE;
1979
1980 fJsonrCnt++; // count object, but do not keep reference
1981
1982 stack = JsonStartObjectWrite(cl, sinfo);
1983 } else {
1984 stack = PushStack(0);
1985 }
1986
1987 stack->fInfo = sinfo;
1988 stack->fIsStreamerInfo = kTRUE;
1989}
1990
1991////////////////////////////////////////////////////////////////////////////////
1992/// Function is called from TStreamerInfo WriteBuffer and ReadBuffer functions
1993/// and decrease level in json structure.
1994
1996{
1997 if (gDebug > 2)
1998 Info("DecrementLevel", "Class: %s", (info ? info->GetClass()->GetName() : "custom"));
1999
2000 TJSONStackObj *stack = Stack();
2001
2002 if (stack->IsStreamerElement()) {
2003
2004 if (IsWriting()) {
2005 if (gDebug > 3)
2006 Info("DecrementLevel", " Perform post-processing elem: %s", stack->fElem->GetName());
2007
2008 PerformPostProcessing(stack);
2009 }
2010
2011 stack = PopStack(); // remove stack of last element
2012 }
2013
2014 if (stack->fInfo != (TStreamerInfo *)info)
2015 Error("DecrementLevel", " Mismatch of streamer info");
2016
2017 PopStack(); // back from data of stack info
2018
2019 if (gDebug > 3)
2020 Info("DecrementLevel", "Class: %s done", (info ? info->GetClass()->GetName() : "custom"));
2021}
2022
2023////////////////////////////////////////////////////////////////////////////////
2024/// Return current streamer info element
2025
2027{
2028 return Stack()->fInfo;
2029}
2030
2031////////////////////////////////////////////////////////////////////////////////
2032/// Function is called from TStreamerInfo WriteBuffer and ReadBuffer functions
2033/// and add/verify next element of json structure
2034/// This calls allows separate data, correspondent to one class member, from another
2035
2037{
2038 if (gDebug > 3)
2039 Info("SetStreamerElementNumber", "Element name %s", elem->GetName());
2040
2041 WorkWithElement(elem, comp_type);
2042}
2043
2044////////////////////////////////////////////////////////////////////////////////
2045/// This is call-back from streamer which indicates
2046/// that class member will be streamed
2047/// Name of element used in JSON
2048
2050{
2051 TJSONStackObj *stack = Stack();
2052 if (!stack) {
2053 Error("WorkWithElement", "stack is empty");
2054 return;
2055 }
2056
2057 if (gDebug > 0)
2058 Info("WorkWithElement", " Start element %s type %d typename %s", elem ? elem->GetName() : "---",
2059 elem ? elem->GetType() : -1, elem ? elem->GetTypeName() : "---");
2060
2061 if (stack->IsStreamerElement()) {
2062 // this is post processing
2063
2064 if (IsWriting()) {
2065 if (gDebug > 3)
2066 Info("WorkWithElement", " Perform post-processing elem: %s", stack->fElem->GetName());
2067 PerformPostProcessing(stack);
2068 }
2069
2070 stack = PopStack(); // go level back
2071 }
2072
2073 fValue.Clear();
2074
2075 if (!stack) {
2076 Error("WorkWithElement", "Lost of stack");
2077 return;
2078 }
2079
2080 TStreamerInfo *info = stack->fInfo;
2081 if (!stack->IsStreamerInfo()) {
2082 Error("WorkWithElement", "Problem in Inc/Dec level");
2083 return;
2084 }
2085
2086 Int_t number = info ? info->GetElements()->IndexOf(elem) : -1;
2087
2088 if (!elem) {
2089 Error("WorkWithElement", "streamer info returns elem = 0");
2090 return;
2091 }
2092
2093 TClass *base_class = elem->IsBase() ? elem->GetClassPointer() : nullptr;
2094
2095 stack = PushStack(0, stack->fNode);
2096 stack->fElem = (TStreamerElement *)elem;
2097 stack->fIsElemOwner = (number < 0);
2098
2099 JsonStartElement(elem, base_class);
2100
2101 if (base_class && IsReading())
2102 stack->fClVersion = base_class->GetClassVersion();
2103
2104 if ((elem->GetType() == TStreamerInfo::kOffsetL + TStreamerInfo::kStreamLoop) && (elem->GetArrayDim() > 0)) {
2105 // array of array, start handling here
2106 stack->fIndx = std::make_unique<TArrayIndexProducer>(elem, -1, fArraySepar.Data());
2107 if (IsWriting())
2108 AppendOutput(stack->fIndx->GetBegin());
2109 }
2110
2111 if (IsReading() && (elem->GetType() > TStreamerInfo::kOffsetP) && (elem->GetType() < TStreamerInfo::kOffsetP + 20)) {
2112 // reading of such array begins with reading of single Char_t value
2113 // it indicates if array should be read or not
2114 stack->PushIntValue(stack->IsJsonString() || (stack->IsJsonArray() > 0) ? 1 : 0);
2115 }
2116}
2117
2118////////////////////////////////////////////////////////////////////////////////
2119/// Should be called in the beginning of custom class streamer.
2120/// Informs buffer data about class which will be streamed now.
2121///
2122/// ClassBegin(), ClassEnd() and ClassMember() should be used in
2123/// custom class streamers to specify which kind of data are
2124/// now streamed. Such information is used to correctly
2125/// convert class data to JSON. Without that functions calls
2126/// classes with custom streamers cannot be used with TBufferJSON
2127
2129{
2130 WorkWithClass(nullptr, cl);
2131}
2132
2133////////////////////////////////////////////////////////////////////////////////
2134/// Should be called at the end of custom streamer
2135/// See TBufferJSON::ClassBegin for more details
2136
2138{
2139 DecrementLevel(0);
2140}
2141
2142////////////////////////////////////////////////////////////////////////////////
2143/// Method indicates name and typename of class member,
2144/// which should be now streamed in custom streamer
2145/// Following combinations are supported:
2146/// 1. name = "ClassName", typeName = 0 or typename==ClassName
2147/// This is a case, when data of parent class "ClassName" should be streamed.
2148/// For instance, if class directly inherited from TObject, custom
2149/// streamer should include following code:
2150/// ~~~{.cpp}
2151/// b.ClassMember("TObject");
2152/// TObject::Streamer(b);
2153/// ~~~
2154/// 2. Basic data type
2155/// ~~~{.cpp}
2156/// b.ClassMember("fInt","Int_t");
2157/// b >> fInt;
2158/// ~~~
2159/// 3. Array of basic data types
2160/// ~~~{.cpp}
2161/// b.ClassMember("fArr","Int_t", 5);
2162/// b.ReadFastArray(fArr, 5);
2163/// ~~~
2164/// 4. Object as data member
2165/// ~~~{.cpp}
2166/// b.ClassMember("fName","TString");
2167/// fName.Streamer(b);
2168/// ~~~
2169/// 5. Pointer on object as data member
2170/// ~~~{.cpp}
2171/// b.ClassMember("fObj","TObject*");
2172/// b.StreamObject(fObj);
2173/// ~~~
2174///
2175/// arrsize1 and arrsize2 arguments (when specified) indicate first and
2176/// second dimension of array. Can be used for array of basic types.
2177/// See ClassBegin() method for more details.
2178
2179void TBufferJSON::ClassMember(const char *name, const char *typeName, Int_t arrsize1, Int_t arrsize2)
2180{
2181 if (!typeName)
2182 typeName = name;
2183
2184 if (!name || (strlen(name) == 0)) {
2185 Error("ClassMember", "Invalid member name");
2186 return;
2187 }
2188
2189 TString tname = typeName;
2190
2191 Int_t typ_id = -1;
2192
2193 if (strcmp(typeName, "raw:data") == 0)
2194 typ_id = TStreamerInfo::kMissing;
2195
2196 if (typ_id < 0) {
2197 TDataType *dt = gROOT->GetType(typeName);
2198 if (dt && (dt->GetType() > 0) && (dt->GetType() < 20))
2199 typ_id = dt->GetType();
2200 }
2201
2202 if (typ_id < 0)
2203 if (strcmp(name, typeName) == 0) {
2204 TClass *cl = TClass::GetClass(tname.Data());
2205 if (cl)
2206 typ_id = TStreamerInfo::kBase;
2207 }
2208
2209 if (typ_id < 0) {
2210 Bool_t isptr = kFALSE;
2211 if (tname[tname.Length() - 1] == '*') {
2212 tname.Resize(tname.Length() - 1);
2213 isptr = kTRUE;
2214 }
2215 TClass *cl = TClass::GetClass(tname.Data());
2216 if (!cl) {
2217 Error("ClassMember", "Invalid class specifier %s", typeName);
2218 return;
2219 }
2220
2221 if (cl->IsTObject())
2223 else
2224 typ_id = isptr ? TStreamerInfo::kAnyp : TStreamerInfo::kAny;
2225
2226 if ((cl == TString::Class()) && !isptr)
2227 typ_id = TStreamerInfo::kTString;
2228 }
2229
2230 TStreamerElement *elem = nullptr;
2231
2232 if (typ_id == TStreamerInfo::kMissing) {
2233 elem = new TStreamerElement(name, "title", 0, typ_id, "raw:data");
2234 } else if (typ_id == TStreamerInfo::kBase) {
2235 TClass *cl = TClass::GetClass(tname.Data());
2236 if (cl) {
2237 TStreamerBase *b = new TStreamerBase(tname.Data(), "title", 0);
2238 b->SetBaseVersion(cl->GetClassVersion());
2239 elem = b;
2240 }
2241 } else if ((typ_id > 0) && (typ_id < 20)) {
2242 elem = new TStreamerBasicType(name, "title", 0, typ_id, typeName);
2243 } else if ((typ_id == TStreamerInfo::kObject) || (typ_id == TStreamerInfo::kTObject) ||
2244 (typ_id == TStreamerInfo::kTNamed)) {
2245 elem = new TStreamerObject(name, "title", 0, tname.Data());
2246 } else if (typ_id == TStreamerInfo::kObjectp) {
2247 elem = new TStreamerObjectPointer(name, "title", 0, tname.Data());
2248 } else if (typ_id == TStreamerInfo::kAny) {
2249 elem = new TStreamerObjectAny(name, "title", 0, tname.Data());
2250 } else if (typ_id == TStreamerInfo::kAnyp) {
2251 elem = new TStreamerObjectAnyPointer(name, "title", 0, tname.Data());
2252 } else if (typ_id == TStreamerInfo::kTString) {
2253 elem = new TStreamerString(name, "title", 0);
2254 }
2255
2256 if (!elem) {
2257 Error("ClassMember", "Invalid combination name = %s type = %s", name, typeName);
2258 return;
2259 }
2260
2261 if (arrsize1 > 0) {
2262 elem->SetArrayDim(arrsize2 > 0 ? 2 : 1);
2263 elem->SetMaxIndex(0, arrsize1);
2264 if (arrsize2 > 0)
2265 elem->SetMaxIndex(1, arrsize2);
2266 }
2267
2268 // we indicate that there is no streamerinfo
2269 WorkWithElement(elem, -1);
2270}
2271
2272////////////////////////////////////////////////////////////////////////////////
2273/// Function is converts TObject and TString structures to more compact representation
2274
2275void TBufferJSON::PerformPostProcessing(TJSONStackObj *stack, const TClass *obj_cl)
2276{
2277 if (stack->fIsPostProcessed)
2278 return;
2279
2280 const TStreamerElement *elem = stack->fElem;
2281
2282 if (!elem && !obj_cl)
2283 return;
2284
2285 stack->fIsPostProcessed = kTRUE;
2286
2287 // when element was written as separate object, close only braces and exit
2288 if (stack->fIsObjStarted) {
2289 AppendOutput("", "}");
2290 return;
2291 }
2292
2293 Bool_t isTObject(kFALSE), isTRef(kFALSE), isTString(kFALSE), isSTLstring(kFALSE), isOffsetPArray(kFALSE),
2294 isTArray(kFALSE);
2295
2296 if (obj_cl) {
2297 if (obj_cl == TObject::Class())
2298 isTObject = kTRUE;
2299 else if (obj_cl == TRef::Class())
2300 isTRef = kTRUE;
2301 else
2302 return;
2303 } else {
2304 const char *typname = elem->IsBase() ? elem->GetName() : elem->GetTypeName();
2305 isTObject = (elem->GetType() == TStreamerInfo::kTObject) || (strcmp("TObject", typname) == 0);
2306 isTString = elem->GetType() == TStreamerInfo::kTString;
2307 isSTLstring = elem->GetType() == TStreamerInfo::kSTLstring;
2308 isOffsetPArray = (elem->GetType() > TStreamerInfo::kOffsetP) && (elem->GetType() < TStreamerInfo::kOffsetP + 20);
2309 isTArray = (strncmp("TArray", typname, 6) == 0);
2310 }
2311
2312 if (isTString || isSTLstring) {
2313 // just remove all kind of string length information
2314
2315 if (gDebug > 3)
2316 Info("PerformPostProcessing", "reformat string value = '%s'", fValue.Data());
2317
2318 stack->fValues.clear();
2319 } else if (isOffsetPArray) {
2320 // basic array with [fN] comment
2321
2322 if (stack->fValues.empty() && (fValue == "0")) {
2323 fValue = "[]";
2324 } else if ((stack->fValues.size() == 1) && (stack->fValues[0] == "1")) {
2325 stack->fValues.clear();
2326 } else {
2327 Error("PerformPostProcessing", "Wrong values for kOffsetP element %s", (elem ? elem->GetName() : "---"));
2328 stack->fValues.clear();
2329 fValue = "[]";
2330 }
2331 } else if (isTObject || isTRef) {
2332 // complex workaround for TObject/TRef streamer
2333 // would be nice if other solution can be found
2334 // Here is not supported TRef on TRef (double reference)
2335
2336 Int_t cnt = stack->fValues.size();
2337 if (fValue.Length() > 0)
2338 cnt++;
2339
2340 if (cnt < 2 || cnt > 3) {
2341 if (gDebug > 0)
2342 Error("PerformPostProcessing", "When storing TObject/TRef, strange number of items %d", cnt);
2343 AppendOutput(stack->NextMemberSeparator(), "\"dummy\"");
2345 } else {
2346 AppendOutput(stack->NextMemberSeparator(), "\"fUniqueID\"");
2348 AppendOutput(stack->fValues[0].c_str());
2349 AppendOutput(stack->NextMemberSeparator(), "\"fBits\"");
2351 AppendOutput((stack->fValues.size() > 1) ? stack->fValues[1].c_str() : fValue.Data());
2352 if (cnt == 3) {
2353 AppendOutput(stack->NextMemberSeparator(), "\"fPID\"");
2355 AppendOutput((stack->fValues.size() > 2) ? stack->fValues[2].c_str() : fValue.Data());
2356 }
2357
2358 stack->fValues.clear();
2359 fValue.Clear();
2360 return;
2361 }
2362
2363 } else if (isTArray) {
2364 // for TArray one deletes complete stack
2365 stack->fValues.clear();
2366 }
2367
2368 if (elem && elem->IsBase() && (fValue.Length() == 0)) {
2369 // here base class data already completely stored
2370 return;
2371 }
2372
2373 if (!stack->fValues.empty()) {
2374 // append element blob data just as abstract array, user is responsible to decode it
2375 AppendOutput("[");
2376 for (auto &blob: stack->fValues) {
2377 AppendOutput(blob.c_str());
2379 }
2380 }
2381
2382 if (fValue.Length() == 0) {
2383 AppendOutput("null");
2384 } else {
2386 fValue.Clear();
2387 }
2388
2389 if (!stack->fValues.empty())
2390 AppendOutput("]");
2391}
2392
2393////////////////////////////////////////////////////////////////////////////////
2394/// suppressed function of TBuffer
2395
2397{
2398 return nullptr;
2399}
2400
2401////////////////////////////////////////////////////////////////////////////////
2402/// suppressed function of TBuffer
2403
2405
2406////////////////////////////////////////////////////////////////////////////////
2407/// read version value from buffer
2408
2410{
2411 Version_t res = cl ? cl->GetClassVersion() : 0;
2412
2413 if (start)
2414 *start = 0;
2415 if (bcnt)
2416 *bcnt = 0;
2417
2418 if (!cl && Stack()->fClVersion) {
2419 res = Stack()->fClVersion;
2420 Stack()->fClVersion = 0;
2421 }
2422
2423 if (gDebug > 3)
2424 Info("ReadVersion", "Result: %d Class: %s", res, (cl ? cl->GetName() : "---"));
2425
2426 return res;
2427}
2428
2429////////////////////////////////////////////////////////////////////////////////
2430/// Ignored in TBufferJSON
2431
2432UInt_t TBufferJSON::WriteVersion(const TClass * /*cl*/, Bool_t /* useBcnt */)
2433{
2434 return 0;
2435}
2436
2437////////////////////////////////////////////////////////////////////////////////
2438/// Read object from buffer. Only used from TBuffer
2439
2440void *TBufferJSON::ReadObjectAny(const TClass *expectedClass)
2441{
2442 if (gDebug > 2)
2443 Info("ReadObjectAny", "From current JSON node");
2444 void *res = JsonReadObject(nullptr, expectedClass);
2445 return res;
2446}
2447
2448////////////////////////////////////////////////////////////////////////////////
2449/// Skip any kind of object from buffer
2450
2452
2453////////////////////////////////////////////////////////////////////////////////
2454/// Write object to buffer. Only used from TBuffer
2455
2456void TBufferJSON::WriteObjectClass(const void *actualObjStart, const TClass *actualClass, Bool_t cacheReuse)
2457{
2458 if (gDebug > 3)
2459 Info("WriteObjectClass", "Class %s", (actualClass ? actualClass->GetName() : " null"));
2460
2461 JsonWriteObject(actualObjStart, actualClass, cacheReuse);
2462}
2463
2464////////////////////////////////////////////////////////////////////////////////
2465/// If value exists, push in the current stack for post-processing
2466
2468{
2469 if (fValue.Length() > 0)
2470 Stack()->PushValue(fValue);
2471}
2472
2473////////////////////////////////////////////////////////////////////////////////
2474/// Read array of Bool_t from buffer
2475
2477{
2478 return JsonReadArray(b);
2479}
2480
2481////////////////////////////////////////////////////////////////////////////////
2482/// Read array of Char_t from buffer
2483
2485{
2486 return JsonReadArray(c);
2487}
2488
2489////////////////////////////////////////////////////////////////////////////////
2490/// Read array of UChar_t from buffer
2491
2493{
2494 return JsonReadArray(c);
2495}
2496
2497////////////////////////////////////////////////////////////////////////////////
2498/// Read array of Short_t from buffer
2499
2501{
2502 return JsonReadArray(h);
2503}
2504
2505////////////////////////////////////////////////////////////////////////////////
2506/// Read array of UShort_t from buffer
2507
2509{
2510 return JsonReadArray(h);
2511}
2512
2513////////////////////////////////////////////////////////////////////////////////
2514/// Read array of Int_t from buffer
2515
2517{
2518 return JsonReadArray(i);
2519}
2520
2521////////////////////////////////////////////////////////////////////////////////
2522/// Read array of UInt_t from buffer
2523
2525{
2526 return JsonReadArray(i);
2527}
2528
2529////////////////////////////////////////////////////////////////////////////////
2530/// Read array of Long_t from buffer
2531
2533{
2534 return JsonReadArray(l);
2535}
2536
2537////////////////////////////////////////////////////////////////////////////////
2538/// Read array of ULong_t from buffer
2539
2541{
2542 return JsonReadArray(l);
2543}
2544
2545////////////////////////////////////////////////////////////////////////////////
2546/// Read array of Long64_t from buffer
2547
2549{
2550 return JsonReadArray(l);
2551}
2552
2553////////////////////////////////////////////////////////////////////////////////
2554/// Read array of ULong64_t from buffer
2555
2557{
2558 return JsonReadArray(l);
2559}
2560
2561////////////////////////////////////////////////////////////////////////////////
2562/// Read array of Float_t from buffer
2563
2565{
2566 return JsonReadArray(f);
2567}
2568
2569////////////////////////////////////////////////////////////////////////////////
2570/// Read array of Double_t from buffer
2571
2573{
2574 return JsonReadArray(d);
2575}
2576
2577////////////////////////////////////////////////////////////////////////////////
2578/// Read static array from JSON - not used
2579
2580template <typename T>
2582{
2583 Info("ReadArray", "Not implemented");
2584 return value ? 1 : 0;
2585}
2586
2587////////////////////////////////////////////////////////////////////////////////
2588/// Read array of Bool_t from buffer
2589
2591{
2592 return JsonReadArray(b);
2593}
2594
2595////////////////////////////////////////////////////////////////////////////////
2596/// Read array of Char_t from buffer
2597
2599{
2600 return JsonReadArray(c);
2601}
2602
2603////////////////////////////////////////////////////////////////////////////////
2604/// Read array of UChar_t from buffer
2605
2607{
2608 return JsonReadArray(c);
2609}
2610
2611////////////////////////////////////////////////////////////////////////////////
2612/// Read array of Short_t from buffer
2613
2615{
2616 return JsonReadArray(h);
2617}
2618
2619////////////////////////////////////////////////////////////////////////////////
2620/// Read array of UShort_t from buffer
2621
2623{
2624 return JsonReadArray(h);
2625}
2626
2627////////////////////////////////////////////////////////////////////////////////
2628/// Read array of Int_t from buffer
2629
2631{
2632 return JsonReadArray(i);
2633}
2634
2635////////////////////////////////////////////////////////////////////////////////
2636/// Read array of UInt_t from buffer
2637
2639{
2640 return JsonReadArray(i);
2641}
2642
2643////////////////////////////////////////////////////////////////////////////////
2644/// Read array of Long_t from buffer
2645
2647{
2648 return JsonReadArray(l);
2649}
2650
2651////////////////////////////////////////////////////////////////////////////////
2652/// Read array of ULong_t from buffer
2653
2655{
2656 return JsonReadArray(l);
2657}
2658
2659////////////////////////////////////////////////////////////////////////////////
2660/// Read array of Long64_t from buffer
2661
2663{
2664 return JsonReadArray(l);
2665}
2666
2667////////////////////////////////////////////////////////////////////////////////
2668/// Read array of ULong64_t from buffer
2669
2671{
2672 return JsonReadArray(l);
2673}
2674
2675////////////////////////////////////////////////////////////////////////////////
2676/// Read array of Float_t from buffer
2677
2679{
2680 return JsonReadArray(f);
2681}
2682
2683////////////////////////////////////////////////////////////////////////////////
2684/// Read array of Double_t from buffer
2685
2687{
2688 return JsonReadArray(d);
2689}
2690
2691////////////////////////////////////////////////////////////////////////////////
2692/// Template method to read array from the JSON
2693
2694template <typename T>
2695R__ALWAYS_INLINE void TBufferJSON::JsonReadFastArray(T *arr, Int_t arrsize, bool asstring)
2696{
2697 if (!arr || (arrsize <= 0))
2698 return;
2699 nlohmann::json *json = Stack()->fNode;
2700 if (gDebug > 2)
2701 Info("ReadFastArray", "Reading array sz %d from JSON %s", arrsize, json->dump().substr(0, 30).c_str());
2702 auto indexes = Stack()->MakeReadIndexes();
2703 if (indexes) { /* at least two dims */
2704 TArrayI &indx = indexes->GetIndices();
2705 Int_t lastdim = indx.GetSize() - 1;
2706 if (indexes->TotalLength() != arrsize)
2707 Error("ReadFastArray", "Mismatch %d-dim array sizes %d %d", lastdim + 1, arrsize, (int)indexes->TotalLength());
2708 for (int cnt = 0; cnt < arrsize; ++cnt) {
2709 nlohmann::json *elem = &(json->at(indx[0]));
2710 for (int k = 1; k < lastdim; ++k)
2711 elem = &((*elem)[indx[k]]);
2712 arr[cnt] = asstring ? elem->get<std::string>()[indx[lastdim]] : (*elem)[indx[lastdim]].get<T>();
2713 indexes->NextSeparator();
2714 }
2715 } else if (asstring) {
2716 std::string str = json->get<std::string>();
2717 for (int cnt = 0; cnt < arrsize; ++cnt)
2718 arr[cnt] = (cnt < (int)str.length()) ? str[cnt] : 0;
2719 } else if (json->is_object() && (json->count("$arr") == 1)) {
2720 if (json->at("len").get<int>() != arrsize)
2721 Error("ReadFastArray", "Mismatch compressed array size %d %d", arrsize, json->at("len").get<int>());
2722 for (int cnt = 0; cnt < arrsize; ++cnt)
2723 arr[cnt] = 0;
2724 int p = 0, id = 0;
2725 std::string idname = "", pname, vname, nname;
2726 while (p < arrsize) {
2727 pname = std::string("p") + idname;
2728 if (json->count(pname) == 1)
2729 p = json->at(pname).get<int>();
2730 vname = std::string("v") + idname;
2731 if (json->count(vname) != 1)
2732 break;
2733 nlohmann::json &v = json->at(vname);
2734 if (v.is_array()) {
2735 for (unsigned sub = 0; sub < v.size(); ++sub)
2736 arr[p++] = v[sub].get<T>();
2737 } else {
2738 nname = std::string("n") + idname;
2739 unsigned ncopy = (json->count(nname) == 1) ? json->at(nname).get<unsigned>() : 1;
2740 for (unsigned sub = 0; sub < ncopy; ++sub)
2741 arr[p++] = v.get<T>();
2742 }
2743 idname = std::to_string(++id);
2744 }
2745 } else {
2746 if ((int)json->size() != arrsize)
2747 Error("ReadFastArray", "Mismatch array sizes %d %d", arrsize, (int)json->size());
2748 for (int cnt = 0; cnt < arrsize; ++cnt)
2749 arr[cnt] = json->at(cnt).get<T>();
2750 }
2751}
2752
2753////////////////////////////////////////////////////////////////////////////////
2754/// read array of Bool_t from buffer
2755
2757{
2759}
2760
2761////////////////////////////////////////////////////////////////////////////////
2762/// read array of Char_t from buffer
2763
2765{
2766 JsonReadFastArray(c, n, true);
2767}
2768
2769////////////////////////////////////////////////////////////////////////////////
2770/// read array of Char_t from buffer
2771
2773{
2774 JsonReadFastArray(c, n, true);
2775}
2776
2777////////////////////////////////////////////////////////////////////////////////
2778/// read array of UChar_t from buffer
2779
2781{
2783}
2784
2785////////////////////////////////////////////////////////////////////////////////
2786/// read array of Short_t from buffer
2787
2789{
2791}
2792
2793////////////////////////////////////////////////////////////////////////////////
2794/// read array of UShort_t from buffer
2795
2797{
2799}
2800
2801////////////////////////////////////////////////////////////////////////////////
2802/// read array of Int_t from buffer
2803
2805{
2806 JsonReadFastArray(i, n);
2807}
2808
2809////////////////////////////////////////////////////////////////////////////////
2810/// read array of UInt_t from buffer
2811
2813{
2814 JsonReadFastArray(i, n);
2815}
2816
2817////////////////////////////////////////////////////////////////////////////////
2818/// read array of Long_t from buffer
2819
2821{
2823}
2824
2825////////////////////////////////////////////////////////////////////////////////
2826/// read array of ULong_t from buffer
2827
2829{
2831}
2832
2833////////////////////////////////////////////////////////////////////////////////
2834/// read array of Long64_t from buffer
2835
2837{
2839}
2840
2841////////////////////////////////////////////////////////////////////////////////
2842/// read array of ULong64_t from buffer
2843
2845{
2847}
2848
2849////////////////////////////////////////////////////////////////////////////////
2850/// read array of Float_t from buffer
2851
2853{
2855}
2856
2857////////////////////////////////////////////////////////////////////////////////
2858/// read array of Double_t from buffer
2859
2861{
2863}
2864
2865////////////////////////////////////////////////////////////////////////////////
2866/// Read an array of 'n' objects from the I/O buffer.
2867/// Stores the objects read starting at the address 'start'.
2868/// The objects in the array are assume to be of class 'cl'.
2869/// Copied code from TBufferFile
2870
2871void TBufferJSON::ReadFastArray(void *start, const TClass *cl, Int_t n, TMemberStreamer * /* streamer */,
2872 const TClass * /* onFileClass */)
2873{
2874 if (gDebug > 1)
2875 Info("ReadFastArray", "void* n:%d cl:%s", n, cl->GetName());
2876
2877 // if (streamer) {
2878 // Info("ReadFastArray", "(void*) Calling streamer - not handled correctly");
2879 // streamer->SetOnFileClass(onFileClass);
2880 // (*streamer)(*this, start, 0);
2881 // return;
2882 // }
2883
2884 int objectSize = cl->Size();
2885 char *obj = (char *)start;
2886
2887 TJSONStackObj *stack = Stack();
2888 nlohmann::json *topnode = stack->fNode, *subnode = topnode;
2889 if (stack->fIndx)
2890 subnode = stack->fIndx->ExtractNode(topnode);
2891
2892 TArrayIndexProducer indexes(stack->fElem, n, "");
2893
2894 if (gDebug > 1)
2895 Info("ReadFastArray", "Indexes ndim:%d totallen:%d", indexes.NumDimensions(), indexes.TotalLength());
2896
2897 for (Int_t j = 0; j < n; j++, obj += objectSize) {
2898
2899 stack->fNode = indexes.ExtractNode(subnode);
2900
2901 JsonReadObject(obj, cl);
2902 }
2903
2904 // restore top node - show we use stack here?
2905 stack->fNode = topnode;
2906}
2907
2908////////////////////////////////////////////////////////////////////////////////
2909/// redefined here to avoid warning message from gcc
2910
2911void TBufferJSON::ReadFastArray(void **start, const TClass *cl, Int_t n, Bool_t isPreAlloc,
2912 TMemberStreamer * /* streamer */, const TClass * /* onFileClass */)
2913{
2914 if (gDebug > 1)
2915 Info("ReadFastArray", "void** n:%d cl:%s prealloc:%s", n, cl->GetName(), (isPreAlloc ? "true" : "false"));
2916
2917 // if (streamer) {
2918 // Info("ReadFastArray", "(void**) Calling streamer - not handled correctly");
2919 // if (isPreAlloc) {
2920 // for (Int_t j = 0; j < n; j++) {
2921 // if (!start[j])
2922 // start[j] = cl->New();
2923 // }
2924 // }
2925 // streamer->SetOnFileClass(onFileClass);
2926 // (*streamer)(*this, (void *)start, 0);
2927 // return;
2928 // }
2929
2930 TJSONStackObj *stack = Stack();
2931 nlohmann::json *topnode = stack->fNode, *subnode = topnode;
2932 if (stack->fIndx)
2933 subnode = stack->fIndx->ExtractNode(topnode);
2934
2935 TArrayIndexProducer indexes(stack->fElem, n, "");
2936
2937 for (Int_t j = 0; j < n; j++) {
2938
2939 stack->fNode = indexes.ExtractNode(subnode);
2940
2941 if (!isPreAlloc) {
2942 void *old = start[j];
2943 start[j] = JsonReadObject(nullptr, cl);
2944 if (old && old != start[j] && TStreamerInfo::CanDelete())
2945 (const_cast<TClass *>(cl))->Destructor(old, kFALSE); // call delete and destruct
2946 } else {
2947 if (!start[j])
2948 start[j] = (const_cast<TClass *>(cl))->New();
2949 JsonReadObject(start[j], cl);
2950 }
2951 }
2952
2953 stack->fNode = topnode;
2954}
2955
2956template <typename T>
2957R__ALWAYS_INLINE void TBufferJSON::JsonWriteArrayCompress(const T *vname, Int_t arrsize, const char *typname)
2958{
2959 if ((fArrayCompact == 0) || (arrsize < 6)) {
2960 fValue.Append("[");
2961 for (Int_t indx = 0; indx < arrsize; indx++) {
2962 if (indx > 0)
2964 JsonWriteBasic(vname[indx]);
2965 }
2966 fValue.Append("]");
2967 } else {
2968 fValue.Append("{");
2969 fValue.Append(TString::Format("\"$arr\":\"%s\"%s\"len\":%d", typname, fArraySepar.Data(), arrsize));
2970 Int_t aindx(0), bindx(arrsize);
2971 while ((aindx < arrsize) && (vname[aindx] == 0))
2972 aindx++;
2973 while ((aindx < bindx) && (vname[bindx - 1] == 0))
2974 bindx--;
2975 if (aindx < bindx) {
2976 TString suffix("");
2977 Int_t p(aindx), suffixcnt(-1), lastp(0);
2978 while (p < bindx) {
2979 if (vname[p] == 0) {
2980 p++;
2981 continue;
2982 }
2983 Int_t p0(p++), pp(0), nsame(1);
2985 pp = bindx;
2986 p = bindx + 1;
2987 nsame = 0;
2988 }
2989 for (; p <= bindx; ++p) {
2990 if ((p < bindx) && (vname[p] == vname[p - 1])) {
2991 nsame++;
2992 continue;
2993 }
2994 if (vname[p - 1] == 0) {
2995 if (nsame > 9) {
2996 nsame = 0;
2997 break;
2998 }
2999 } else if (nsame > 5) {
3000 if (pp) {
3001 p = pp;
3002 nsame = 0;
3003 } else
3004 pp = p;
3005 break;
3006 }
3007 pp = p;
3008 nsame = 1;
3009 }
3010 if (pp <= p0)
3011 continue;
3012 if (++suffixcnt > 0)
3013 suffix.Form("%d", suffixcnt);
3014 if (p0 != lastp)
3015 fValue.Append(TString::Format("%s\"p%s\":%d", fArraySepar.Data(), suffix.Data(), p0));
3016 lastp = pp; /* remember cursor, it may be the same */
3017 fValue.Append(TString::Format("%s\"v%s\":", fArraySepar.Data(), suffix.Data()));
3018 if ((nsame > 1) || (pp - p0 == 1)) {
3019 JsonWriteBasic(vname[p0]);
3020 if (nsame > 1)
3021 fValue.Append(TString::Format("%s\"n%s\":%d", fArraySepar.Data(), suffix.Data(), nsame));
3022 } else {
3023 fValue.Append("[");
3024 for (Int_t indx = p0; indx < pp; indx++) {
3025 if (indx > p0)
3027 JsonWriteBasic(vname[indx]);
3028 }
3029 fValue.Append("]");
3030 }
3031 }
3032 }
3033 fValue.Append("}");
3034 }
3035}
3036
3037////////////////////////////////////////////////////////////////////////////////
3038/// Write array of Bool_t to buffer
3039
3041{
3042 JsonPushValue();
3043 JsonWriteArrayCompress(b, n, "Bool");
3044}
3045
3046////////////////////////////////////////////////////////////////////////////////
3047/// Write array of Char_t to buffer
3048
3050{
3051 JsonPushValue();
3052 JsonWriteArrayCompress(c, n, "Int8");
3053}
3054
3055////////////////////////////////////////////////////////////////////////////////
3056/// Write array of UChar_t to buffer
3057
3059{
3060 JsonPushValue();
3061 JsonWriteArrayCompress(c, n, "Uint8");
3062}
3063
3064////////////////////////////////////////////////////////////////////////////////
3065/// Write array of Short_t to buffer
3066
3068{
3069 JsonPushValue();
3070 JsonWriteArrayCompress(h, n, "Int16");
3071}
3072
3073////////////////////////////////////////////////////////////////////////////////
3074/// Write array of UShort_t to buffer
3075
3077{
3078 JsonPushValue();
3079 JsonWriteArrayCompress(h, n, "Uint16");
3080}
3081
3082////////////////////////////////////////////////////////////////////////////////
3083/// Write array of Int_ to buffer
3084
3086{
3087 JsonPushValue();
3088 JsonWriteArrayCompress(i, n, "Int32");
3089}
3090
3091////////////////////////////////////////////////////////////////////////////////
3092/// Write array of UInt_t to buffer
3093
3095{
3096 JsonPushValue();
3097 JsonWriteArrayCompress(i, n, "Uint32");
3098}
3099
3100////////////////////////////////////////////////////////////////////////////////
3101/// Write array of Long_t to buffer
3102
3104{
3105 JsonPushValue();
3106 JsonWriteArrayCompress(l, n, "Int64");
3107}
3108
3109////////////////////////////////////////////////////////////////////////////////
3110/// Write array of ULong_t to buffer
3111
3113{
3114 JsonPushValue();
3115 JsonWriteArrayCompress(l, n, "Uint64");
3116}
3117
3118////////////////////////////////////////////////////////////////////////////////
3119/// Write array of Long64_t to buffer
3120
3122{
3123 JsonPushValue();
3124 JsonWriteArrayCompress(l, n, "Int64");
3125}
3126
3127////////////////////////////////////////////////////////////////////////////////
3128/// Write array of ULong64_t to buffer
3129
3131{
3132 JsonPushValue();
3133 JsonWriteArrayCompress(l, n, "Uint64");
3134}
3135
3136////////////////////////////////////////////////////////////////////////////////
3137/// Write array of Float_t to buffer
3138
3140{
3141 JsonPushValue();
3142 JsonWriteArrayCompress(f, n, "Float32");
3143}
3144
3145////////////////////////////////////////////////////////////////////////////////
3146/// Write array of Double_t to buffer
3147
3149{
3150 JsonPushValue();
3151 JsonWriteArrayCompress(d, n, "Float64");
3152}
3153
3154////////////////////////////////////////////////////////////////////////////////
3155/// Template method to write array of arbitrary dimensions
3156/// Different methods can be used for store last array dimension -
3157/// either JsonWriteArrayCompress<T>() or JsonWriteConstChar()
3158
3159template <typename T>
3160R__ALWAYS_INLINE void TBufferJSON::JsonWriteFastArray(const T *arr, Int_t arrsize, const char *typname,
3161 void (TBufferJSON::*method)(const T *, Int_t, const char *))
3162{
3163 JsonPushValue();
3164 if (arrsize <= 0) { /*fJsonrCnt++;*/
3165 fValue.Append("[]");
3166 return;
3167 }
3168
3169 TStreamerElement *elem = Stack()->fElem;
3170 if (elem && (elem->GetArrayDim() > 1) && (elem->GetArrayLength() == arrsize)) {
3171 TArrayI indexes(elem->GetArrayDim() - 1);
3172 indexes.Reset(0);
3173 Int_t cnt = 0, shift = 0, len = elem->GetMaxIndex(indexes.GetSize());
3174 while (cnt >= 0) {
3175 if (indexes[cnt] >= elem->GetMaxIndex(cnt)) {
3176 fValue.Append("]");
3177 indexes[cnt--] = 0;
3178 if (cnt >= 0)
3179 indexes[cnt]++;
3180 continue;
3181 }
3182 fValue.Append(indexes[cnt] == 0 ? "[" : fArraySepar.Data());
3183 if (++cnt == indexes.GetSize()) {
3184 (*this.*method)((arr + shift), len, typname);
3185 indexes[--cnt]++;
3186 shift += len;
3187 }
3188 }
3189 } else {
3190 (*this.*method)(arr, arrsize, typname);
3191 }
3192}
3193
3194////////////////////////////////////////////////////////////////////////////////
3195/// Write array of Bool_t to buffer
3196
3198{
3199 JsonWriteFastArray(b, n, "Bool", &TBufferJSON::JsonWriteArrayCompress<Bool_t>);
3200}
3201
3202////////////////////////////////////////////////////////////////////////////////
3203/// Write array of Char_t to buffer
3204
3206{
3208}
3209
3210////////////////////////////////////////////////////////////////////////////////
3211/// Write array of Char_t to buffer
3212
3214{
3216}
3217
3218////////////////////////////////////////////////////////////////////////////////
3219/// Write array of UChar_t to buffer
3220
3222{
3223 JsonWriteFastArray(c, n, "Uint8", &TBufferJSON::JsonWriteArrayCompress<UChar_t>);
3224}
3225
3226////////////////////////////////////////////////////////////////////////////////
3227/// Write array of Short_t to buffer
3228
3230{
3231 JsonWriteFastArray(h, n, "Int16", &TBufferJSON::JsonWriteArrayCompress<Short_t>);
3232}
3233
3234////////////////////////////////////////////////////////////////////////////////
3235/// Write array of UShort_t to buffer
3236
3238{
3239 JsonWriteFastArray(h, n, "Uint16", &TBufferJSON::JsonWriteArrayCompress<UShort_t>);
3240}
3241
3242////////////////////////////////////////////////////////////////////////////////
3243/// Write array of Int_t to buffer
3244
3246{
3247 JsonWriteFastArray(i, n, "Int32", &TBufferJSON::JsonWriteArrayCompress<Int_t>);
3248}
3249
3250////////////////////////////////////////////////////////////////////////////////
3251/// Write array of UInt_t to buffer
3252
3254{
3255 JsonWriteFastArray(i, n, "Uint32", &TBufferJSON::JsonWriteArrayCompress<UInt_t>);
3256}
3257
3258////////////////////////////////////////////////////////////////////////////////
3259/// Write array of Long_t to buffer
3260
3262{
3263 JsonWriteFastArray(l, n, "Int64", &TBufferJSON::JsonWriteArrayCompress<Long_t>);
3264}
3265
3266////////////////////////////////////////////////////////////////////////////////
3267/// Write array of ULong_t to buffer
3268
3270{
3271 JsonWriteFastArray(l, n, "Uint64", &TBufferJSON::JsonWriteArrayCompress<ULong_t>);
3272}
3273
3274////////////////////////////////////////////////////////////////////////////////
3275/// Write array of Long64_t to buffer
3276
3278{
3279 JsonWriteFastArray(l, n, "Int64", &TBufferJSON::JsonWriteArrayCompress<Long64_t>);
3280}
3281
3282////////////////////////////////////////////////////////////////////////////////
3283/// Write array of ULong64_t to buffer
3284
3286{
3287 JsonWriteFastArray(l, n, "Uint64", &TBufferJSON::JsonWriteArrayCompress<ULong64_t>);
3288}
3289
3290////////////////////////////////////////////////////////////////////////////////
3291/// Write array of Float_t to buffer
3292
3294{
3295 JsonWriteFastArray(f, n, "Float32", &TBufferJSON::JsonWriteArrayCompress<Float_t>);
3296}
3297
3298////////////////////////////////////////////////////////////////////////////////
3299/// Write array of Double_t to buffer
3300
3302{
3303 JsonWriteFastArray(d, n, "Float64", &TBufferJSON::JsonWriteArrayCompress<Double_t>);
3304}
3305
3306////////////////////////////////////////////////////////////////////////////////
3307/// Recall TBuffer function to avoid gcc warning message
3308
3309void TBufferJSON::WriteFastArray(void *start, const TClass *cl, Int_t n, TMemberStreamer * /* streamer */)
3310{
3311 if (gDebug > 2)
3312 Info("WriteFastArray", "void *start cl:%s n:%d", cl ? cl->GetName() : "---", n);
3313
3314 // if (streamer) {
3315 // JsonDisablePostprocessing();
3316 // (*streamer)(*this, start, 0);
3317 // return;
3318 // }
3319
3320 if (n < 0) {
3321 // special handling of empty StreamLoop
3322 AppendOutput("null");
3324 } else {
3325
3326 char *obj = (char *)start;
3327 if (!n)
3328 n = 1;
3329 int size = cl->Size();
3330
3331 TArrayIndexProducer indexes(Stack()->fElem, n, fArraySepar.Data());
3332
3333 if (indexes.IsArray()) {
3335 AppendOutput(indexes.GetBegin());
3336 }
3337
3338 for (Int_t j = 0; j < n; j++, obj += size) {
3339
3340 if (j > 0)
3341 AppendOutput(indexes.NextSeparator());
3342
3343 JsonWriteObject(obj, cl, kFALSE);
3344
3345 if (indexes.IsArray() && (fValue.Length() > 0)) {
3347 fValue.Clear();
3348 }
3349 }
3350
3351 if (indexes.IsArray())
3352 AppendOutput(indexes.GetEnd());
3353 }
3354
3355 if (Stack()->fIndx)
3356 AppendOutput(Stack()->fIndx->NextSeparator());
3357}
3358
3359////////////////////////////////////////////////////////////////////////////////
3360/// Recall TBuffer function to avoid gcc warning message
3361
3362Int_t TBufferJSON::WriteFastArray(void **start, const TClass *cl, Int_t n, Bool_t isPreAlloc,
3363 TMemberStreamer * /* streamer */)
3364{
3365 if (gDebug > 2)
3366 Info("WriteFastArray", "void **startp cl:%s n:%d", cl->GetName(), n);
3367
3368 // if (streamer) {
3369 // JsonDisablePostprocessing();
3370 // (*streamer)(*this, (void *)start, 0);
3371 // return 0;
3372 // }
3373
3374 if (n <= 0)
3375 return 0;
3376
3377 Int_t res = 0;
3378
3379 TArrayIndexProducer indexes(Stack()->fElem, n, fArraySepar.Data());
3380
3381 if (indexes.IsArray()) {
3383 AppendOutput(indexes.GetBegin());
3384 }
3385
3386 for (Int_t j = 0; j < n; j++) {
3387
3388 if (j > 0)
3389 AppendOutput(indexes.NextSeparator());
3390
3391 if (!isPreAlloc) {
3392 res |= WriteObjectAny(start[j], cl);
3393 } else {
3394 if (!start[j])
3395 start[j] = (const_cast<TClass *>(cl))->New();
3396 // ((TClass*)cl)->Streamer(start[j],*this);
3397 JsonWriteObject(start[j], cl, kFALSE);
3398 }
3399
3400 if (indexes.IsArray() && (fValue.Length() > 0)) {
3402 fValue.Clear();
3403 }
3404 }
3405
3406 if (indexes.IsArray())
3407 AppendOutput(indexes.GetEnd());
3408
3409 if (Stack()->fIndx)
3410 AppendOutput(Stack()->fIndx->NextSeparator());
3411
3412 return res;
3413}
3414
3415////////////////////////////////////////////////////////////////////////////////
3416/// stream object to/from buffer
3417
3418void TBufferJSON::StreamObject(void *obj, const TClass *cl, const TClass * /* onfileClass */)
3419{
3420 if (gDebug > 3)
3421 Info("StreamObject", "Class: %s", (cl ? cl->GetName() : "none"));
3422
3423 if (IsWriting())
3424 JsonWriteObject(obj, cl);
3425 else
3426 JsonReadObject(obj, cl);
3427}
3428
3429////////////////////////////////////////////////////////////////////////////////
3430/// Template function to read basic value from JSON
3431
3432template <typename T>
3434{
3435 value = Stack()->GetStlNode()->get<T>();
3436}
3437
3438////////////////////////////////////////////////////////////////////////////////
3439/// Reads Bool_t value from buffer
3440
3442{
3443 JsonReadBasic(val);
3444}
3445
3446////////////////////////////////////////////////////////////////////////////////
3447/// Reads Char_t value from buffer
3448
3450{
3451 if (!Stack()->fValues.empty())
3452 val = (Char_t)Stack()->PopIntValue();
3453 else
3454 val = Stack()->GetStlNode()->get<Char_t>();
3455}
3456
3457////////////////////////////////////////////////////////////////////////////////
3458/// Reads UChar_t value from buffer
3459
3461{
3462 JsonReadBasic(val);
3463}
3464
3465////////////////////////////////////////////////////////////////////////////////
3466/// Reads Short_t value from buffer
3467
3469{
3470 JsonReadBasic(val);
3471}
3472
3473////////////////////////////////////////////////////////////////////////////////
3474/// Reads UShort_t value from buffer
3475
3477{
3478 JsonReadBasic(val);
3479}
3480
3481////////////////////////////////////////////////////////////////////////////////
3482/// Reads Int_t value from buffer
3483
3485{
3486 if (!Stack()->fValues.empty())
3487 val = Stack()->PopIntValue();
3488 else
3489 JsonReadBasic(val);
3490}
3491
3492////////////////////////////////////////////////////////////////////////////////
3493/// Reads UInt_t value from buffer
3494
3496{
3497 JsonReadBasic(val);
3498}
3499
3500////////////////////////////////////////////////////////////////////////////////
3501/// Reads Long_t value from buffer
3502
3504{
3505 JsonReadBasic(val);
3506}
3507
3508////////////////////////////////////////////////////////////////////////////////
3509/// Reads ULong_t value from buffer
3510
3512{
3513 JsonReadBasic(val);
3514}
3515
3516////////////////////////////////////////////////////////////////////////////////
3517/// Reads Long64_t value from buffer
3518
3520{
3521 JsonReadBasic(val);
3522}
3523
3524////////////////////////////////////////////////////////////////////////////////
3525/// Reads ULong64_t value from buffer
3526
3528{
3529 JsonReadBasic(val);
3530}
3531
3532////////////////////////////////////////////////////////////////////////////////
3533/// Reads Float_t value from buffer
3534
3536{
3537 nlohmann::json *json = Stack()->GetStlNode();
3538 if (json->is_null())
3539 val = std::numeric_limits<Float_t>::quiet_NaN();
3540 else
3541 val = json->get<Float_t>();
3542}
3543
3544////////////////////////////////////////////////////////////////////////////////
3545/// Reads Double_t value from buffer
3546
3548{
3549 nlohmann::json *json = Stack()->GetStlNode();
3550 if (json->is_null())
3551 val = std::numeric_limits<Double_t>::quiet_NaN();
3552 else
3553 val = json->get<Double_t>();
3554}
3555
3556////////////////////////////////////////////////////////////////////////////////
3557/// Reads array of characters from buffer
3558
3560{
3561 Error("ReadCharP", "Not implemented");
3562}
3563
3564////////////////////////////////////////////////////////////////////////////////
3565/// Reads a TString
3566
3568{
3569 std::string str;
3570 JsonReadBasic(str);
3571 val = str.c_str();
3572}
3573
3574////////////////////////////////////////////////////////////////////////////////
3575/// Reads a std::string
3576
3577void TBufferJSON::ReadStdString(std::string *val)
3578{
3579 JsonReadBasic(*val);
3580}
3581
3582////////////////////////////////////////////////////////////////////////////////
3583/// Reads a char* string
3584
3586{
3587 std::string str;
3588 JsonReadBasic(str);
3589
3590 if (s) {
3591 delete[] s;
3592 s = nullptr;
3593 }
3594
3595 std::size_t nch = str.length();
3596 if (nch > 0) {
3597 s = new char[nch + 1];
3598 memcpy(s, str.c_str(), nch);
3599 s[nch] = 0;
3600 }
3601}
3602
3603////////////////////////////////////////////////////////////////////////////////
3604/// Writes Bool_t value to buffer
3605
3607{
3608 JsonPushValue();
3610}
3611
3612////////////////////////////////////////////////////////////////////////////////
3613/// Writes Char_t value to buffer
3614
3616{
3617 JsonPushValue();
3619}
3620
3621////////////////////////////////////////////////////////////////////////////////
3622/// Writes UChar_t value to buffer
3623
3625{
3626 JsonPushValue();
3628}
3629
3630////////////////////////////////////////////////////////////////////////////////
3631/// Writes Short_t value to buffer
3632
3634{
3635 JsonPushValue();
3637}
3638
3639////////////////////////////////////////////////////////////////////////////////
3640/// Writes UShort_t value to buffer
3641
3643{
3644 JsonPushValue();
3646}
3647
3648////////////////////////////////////////////////////////////////////////////////
3649/// Writes Int_t value to buffer
3650
3652{
3653 JsonPushValue();
3654 JsonWriteBasic(i);
3655}
3656
3657////////////////////////////////////////////////////////////////////////////////
3658/// Writes UInt_t value to buffer
3659
3661{
3662 JsonPushValue();
3663 JsonWriteBasic(i);
3664}
3665
3666////////////////////////////////////////////////////////////////////////////////
3667/// Writes Long_t value to buffer
3668
3670{
3671 JsonPushValue();
3673}
3674
3675////////////////////////////////////////////////////////////////////////////////
3676/// Writes ULong_t value to buffer
3677
3679{
3680 JsonPushValue();
3682}
3683
3684////////////////////////////////////////////////////////////////////////////////
3685/// Writes Long64_t value to buffer
3686
3688{
3689 JsonPushValue();
3691}
3692
3693////////////////////////////////////////////////////////////////////////////////
3694/// Writes ULong64_t value to buffer
3695
3697{
3698 JsonPushValue();
3700}
3701
3702////////////////////////////////////////////////////////////////////////////////
3703/// Writes Float_t value to buffer
3704
3706{
3707 JsonPushValue();
3709}
3710
3711////////////////////////////////////////////////////////////////////////////////
3712/// Writes Double_t value to buffer
3713
3715{
3716 JsonPushValue();
3718}
3719
3720////////////////////////////////////////////////////////////////////////////////
3721/// Writes array of characters to buffer
3722
3724{
3725 JsonPushValue();
3726
3728}
3729
3730////////////////////////////////////////////////////////////////////////////////
3731/// Writes a TString
3732
3734{
3735 JsonPushValue();
3736
3737 JsonWriteConstChar(s.Data(), s.Length());
3738}
3739
3740////////////////////////////////////////////////////////////////////////////////
3741/// Writes a std::string
3742
3743void TBufferJSON::WriteStdString(const std::string *s)
3744{
3745 JsonPushValue();
3746
3747 if (s)
3748 JsonWriteConstChar(s->c_str(), s->length());
3749 else
3750 JsonWriteConstChar("", 0);
3751}
3752
3753////////////////////////////////////////////////////////////////////////////////
3754/// Writes a char*
3755
3757{
3758 JsonPushValue();
3759
3761}
3762
3763////////////////////////////////////////////////////////////////////////////////
3764/// converts Char_t to string and add to json value buffer
3765
3767{
3768 char buf[50];
3769 snprintf(buf, sizeof(buf), "%d", value);
3770 fValue.Append(buf);
3771}
3772
3773////////////////////////////////////////////////////////////////////////////////
3774/// converts Short_t to string and add to json value buffer
3775
3777{
3778 char buf[50];
3779 snprintf(buf, sizeof(buf), "%hd", value);
3780 fValue.Append(buf);
3781}
3782
3783////////////////////////////////////////////////////////////////////////////////
3784/// converts Int_t to string and add to json value buffer
3785
3787{
3788 char buf[50];
3789 snprintf(buf, sizeof(buf), "%d", value);
3790 fValue.Append(buf);
3791}
3792
3793////////////////////////////////////////////////////////////////////////////////
3794/// converts Long_t to string and add to json value buffer
3795
3797{
3798 char buf[50];
3799 snprintf(buf, sizeof(buf), "%ld", value);
3800 fValue.Append(buf);
3801}
3802
3803////////////////////////////////////////////////////////////////////////////////
3804/// converts Long64_t to string and add to json value buffer
3805
3807{
3808 fValue.Append(std::to_string(value).c_str());
3809}
3810
3811////////////////////////////////////////////////////////////////////////////////
3812/// converts Float_t to string and add to json value buffer
3813
3815{
3816 if (std::isinf(value)) {
3817 fValue.Append((value < 0.) ? "-2e308" : "2e308"); // Number.MAX_VALUE is approx 1.79e308
3818 } else if (std::isnan(value)) {
3819 fValue.Append("null");
3820 } else {
3821 char buf[200];
3822 ConvertFloat(value, buf, sizeof(buf));
3823 fValue.Append(buf);
3824 }
3825}
3826
3827////////////////////////////////////////////////////////////////////////////////
3828/// converts Double_t to string and add to json value buffer
3829
3831{
3832 if (std::isinf(value)) {
3833 fValue.Append((value < 0.) ? "-2e308" : "2e308"); // Number.MAX_VALUE is approx 1.79e308
3834 } else if (std::isnan(value)) {
3835 fValue.Append("null");
3836 } else {
3837 char buf[200];
3838 ConvertDouble(value, buf, sizeof(buf));
3839 fValue.Append(buf);
3840 }
3841}
3842
3843////////////////////////////////////////////////////////////////////////////////
3844/// converts Bool_t to string and add to json value buffer
3845
3847{
3848 fValue.Append(value ? "true" : "false");
3849}
3850
3851////////////////////////////////////////////////////////////////////////////////
3852/// converts UChar_t to string and add to json value buffer
3853
3855{
3856 char buf[50];
3857 snprintf(buf, sizeof(buf), "%u", value);
3858 fValue.Append(buf);
3859}
3860
3861////////////////////////////////////////////////////////////////////////////////
3862/// converts UShort_t to string and add to json value buffer
3863
3865{
3866 char buf[50];
3867 snprintf(buf, sizeof(buf), "%hu", value);
3868 fValue.Append(buf);
3869}
3870
3871////////////////////////////////////////////////////////////////////////////////
3872/// converts UInt_t to string and add to json value buffer
3873
3875{
3876 char buf[50];
3877 snprintf(buf, sizeof(buf), "%u", value);
3878 fValue.Append(buf);
3879}
3880
3881////////////////////////////////////////////////////////////////////////////////
3882/// converts ULong_t to string and add to json value buffer
3883
3885{
3886 char buf[50];
3887 snprintf(buf, sizeof(buf), "%lu", value);
3888 fValue.Append(buf);
3889}
3890
3891////////////////////////////////////////////////////////////////////////////////
3892/// converts ULong64_t to string and add to json value buffer
3893
3895{
3896 fValue.Append(std::to_string(value).c_str());
3897}
3898
3899////////////////////////////////////////////////////////////////////////////////
3900/// writes string value, processing all kind of special characters
3901
3902void TBufferJSON::JsonWriteConstChar(const char *value, Int_t len, const char * /* typname */)
3903{
3904 if (!value) {
3905
3906 fValue.Append("\"\"");
3907
3908 } else {
3909
3910 fValue.Append("\"");
3911
3912 if (len < 0)
3913 len = strlen(value);
3914
3915 for (Int_t n = 0; n < len; n++) {
3916 char c = value[n];
3917 if (c == 0)
3918 break;
3919 switch (c) {
3920 case '\n': fValue.Append("\\n"); break;
3921 case '\t': fValue.Append("\\t"); break;
3922 case '\"': fValue.Append("\\\""); break;
3923 case '\\': fValue.Append("\\\\"); break;
3924 case '\b': fValue.Append("\\b"); break;
3925 case '\f': fValue.Append("\\f"); break;
3926 case '\r': fValue.Append("\\r"); break;
3927 case '/': fValue.Append("\\/"); break;
3928 default:
3929 if ((c > 31) && (c < 127))
3930 fValue.Append(c);
3931 else
3932 fValue.Append(TString::Format("\\u%04x", (unsigned)c));
3933 }
3934 }
3935
3936 fValue.Append("\"");
3937 }
3938}
3939
3940////////////////////////////////////////////////////////////////////////////////
3941/// Read data of base class.
3942
3944{
3945 if (elem->GetClassPointer() == TObject::Class()) {
3947 } else {
3948 TBufferText::ReadBaseClass(start, elem);
3949 }
3950}
void Class()
Definition: Class.C:29
SVector< double, 2 > v
Definition: Dict.h:5
PyObject * fValue
#define R__ALWAYS_INLINE
Definition: RConfig.hxx:570
#define d(i)
Definition: RSha256.hxx:102
#define b(i)
Definition: RSha256.hxx:100
#define f(i)
Definition: RSha256.hxx:104
#define c(i)
Definition: RSha256.hxx:101
#define h(i)
Definition: RSha256.hxx:106
static RooMathCoreReg dummy
unsigned short UShort_t
Definition: RtypesCore.h:36
int Int_t
Definition: RtypesCore.h:41
short Version_t
Definition: RtypesCore.h:61
unsigned char UChar_t
Definition: RtypesCore.h:34
char Char_t
Definition: RtypesCore.h:29
unsigned int UInt_t
Definition: RtypesCore.h:42
const Bool_t kFALSE
Definition: RtypesCore.h:88
unsigned long ULong_t
Definition: RtypesCore.h:51
long Long_t
Definition: RtypesCore.h:50
bool Bool_t
Definition: RtypesCore.h:59
short Short_t
Definition: RtypesCore.h:35
double Double_t
Definition: RtypesCore.h:55
long long Long64_t
Definition: RtypesCore.h:69
unsigned long long ULong64_t
Definition: RtypesCore.h:70
float Float_t
Definition: RtypesCore.h:53
const Bool_t kTRUE
Definition: RtypesCore.h:87
#define BIT(n)
Definition: Rtypes.h:83
#define ClassImp(name)
Definition: Rtypes.h:365
R__EXTERN Int_t gDebug
Definition: Rtypes.h:91
@ json_stdstring
@ json_TCollection
@ json_TString
@ json_TArray
@ kNoType_t
Definition: TDataType.h:33
@ kFloat_t
Definition: TDataType.h:31
@ kULong64_t
Definition: TDataType.h:32
@ kInt_t
Definition: TDataType.h:30
@ kchar
Definition: TDataType.h:31
@ kLong_t
Definition: TDataType.h:30
@ kDouble32_t
Definition: TDataType.h:31
@ kShort_t
Definition: TDataType.h:29
@ kBool_t
Definition: TDataType.h:32
@ kBits
Definition: TDataType.h:34
@ kULong_t
Definition: TDataType.h:30
@ kLong64_t
Definition: TDataType.h:32
@ kVoid_t
Definition: TDataType.h:35
@ kUShort_t
Definition: TDataType.h:29
@ kDouble_t
Definition: TDataType.h:31
@ kCharStar
Definition: TDataType.h:34
@ kChar_t
Definition: TDataType.h:29
@ kUChar_t
Definition: TDataType.h:29
@ kCounter
Definition: TDataType.h:34
@ kUInt_t
Definition: TDataType.h:30
@ kFloat16_t
Definition: TDataType.h:33
@ kOther_t
Definition: TDataType.h:32
void Error(const char *location, const char *msgfmt,...)
char name[80]
Definition: TGX11.cxx:109
char idname[128]
Definition: THbookFile.cxx:88
int isnan(double)
#define gROOT
Definition: TROOT.h:414
char * Form(const char *fmt,...)
T1 fFirst
Definition: X11Events.mm:86
#define free
Definition: civetweb.c:1539
#define snprintf
Definition: civetweb.c:1540
#define malloc
Definition: civetweb.c:1536
Array of integers (32 bits per element).
Definition: TArrayI.h:27
void Set(Int_t n)
Set size of this array to n ints.
Definition: TArrayI.cxx:105
void Reset()
Definition: TArrayI.h:47
Abstract array base class.
Definition: TArray.h:31
Int_t GetSize() const
Definition: TArray.h:47
virtual void GetMappedObject(UInt_t tag, void *&ptr, TClass *&ClassPtr) const
Retrieve the object stored in the buffer's object map at 'tag' Set ptr and ClassPtr respectively to t...
Definition: TBufferIO.cxx:260
virtual void MapObject(const TObject *obj, UInt_t offset=1)
Add object to the fMap container.
Definition: TBufferIO.cxx:163
Long64_t GetObjectTag(const void *obj)
Returns tag for specified object from objects map (if exists) Returns 0 if object not included into o...
Definition: TBufferIO.cxx:277
virtual Int_t WriteObjectAny(const void *obj, const TClass *ptrClass, Bool_t cacheReuse=kTRUE)
Write object to I/O buffer.
Definition: TBufferIO.cxx:492
virtual void InitMap()
Create the fMap container and initialize them with the null object.
Definition: TBufferIO.cxx:129
Class for serializing object to and from JavaScript Object Notation (JSON) format.
Definition: TBufferJSON.h:29
virtual void WriteLong64(Long64_t l)
Writes Long64_t value to buffer.
R__ALWAYS_INLINE void JsonWriteArrayCompress(const T *vname, Int_t arrsize, const char *typname)
virtual TClass * ReadClass(const TClass *cl=nullptr, UInt_t *objTag=nullptr)
suppressed function of TBuffer
void JsonWriteBasic(Char_t value)
converts Char_t to string and add to json value buffer
void JsonWriteCollection(TCollection *obj, const TClass *objClass)
store content of ROOT collection
virtual void WriteStdString(const std::string *s)
Writes a std::string.
TString fSemicolon
! depending from compression level, " : " or ":"
Definition: TBufferJSON.h:319
Int_t fCompact
! 0 - no any compression, 1 - no spaces in the begin, 2 - no new lines, 3 - no spaces at all
Definition: TBufferJSON.h:317
virtual void WriteUShort(UShort_t s)
Writes UShort_t value to buffer.
virtual void WriteUInt(UInt_t i)
Writes UInt_t value to buffer.
virtual Version_t ReadVersion(UInt_t *start=nullptr, UInt_t *bcnt=nullptr, const TClass *cl=nullptr)
read version value from buffer
static TObject * ConvertFromJSON(const char *str)
Read TObject-based class from JSON, produced by ConvertToJSON() method.
virtual void ReadLong(Long_t &l)
Reads Long_t value from buffer.
TString fValue
! buffer for current value
Definition: TBufferJSON.h:314
std::deque< TJSONStackObj * > fStack
! hierarchy of currently streamed element
Definition: TBufferJSON.h:316
TJSONStackObj * Stack()
Definition: TBufferJSON.h:252
virtual void WriteChar(Char_t c)
Writes Char_t value to buffer.
virtual void ClassBegin(const TClass *, Version_t=-1)
Should be called in the beginning of custom class streamer.
virtual void WriteDouble(Double_t d)
Writes Double_t value to buffer.
static TString ConvertToJSON(const TObject *obj, Int_t compact=0, const char *member_name=nullptr)
Converts object, inherited from TObject class, to JSON string Lower digit of compact parameter define...
virtual UInt_t WriteVersion(const TClass *cl, Bool_t useBcnt=kFALSE)
Ignored in TBufferJSON.
void PerformPostProcessing(TJSONStackObj *stack, const TClass *obj_cl=nullptr)
Function is converts TObject and TString structures to more compact representation.
virtual void ReadUInt(UInt_t &i)
Reads UInt_t value from buffer.
virtual void WriteInt(Int_t i)
Writes Int_t value to buffer.
virtual void ReadFastArrayString(Char_t *c, Int_t n)
read array of Char_t from buffer
virtual void ReadShort(Short_t &s)
Reads Short_t value from buffer.
static Int_t ExportToFile(const char *filename, const TObject *obj, const char *option=nullptr)
Convert object into JSON and store in text file Returns size of the produce file Used in TObject::Sav...
R__ALWAYS_INLINE Int_t JsonReadArray(T *value)
Read static array from JSON - not used.
TString fNumericLocale
! stored value of setlocale(LC_NUMERIC), which should be recovered at the end
Definition: TBufferJSON.h:322
void SetTypeversionTag(const char *tag=nullptr)
Configures _typeversion tag in JSON One can specify name of the JSON tag like "_typeversion" or "$tv"...
TString fTypeVersionTag
! JSON member used to store class version, default empty
Definition: TBufferJSON.h:324
virtual Int_t ReadArray(Bool_t *&b)
Read array of Bool_t from buffer.
TJSONStackObj * PushStack(Int_t inclevel=0, void *readnode=nullptr)
add new level to the structures stack
TBufferJSON(TBuffer::EMode mode=TBuffer::kWrite)
Creates buffer object to serialize data into json.
void JsonDisablePostprocessing()
disable post-processing of the code
void WorkWithElement(TStreamerElement *elem, Int_t)
This is call-back from streamer which indicates that class member will be streamed Name of element us...
virtual void ReadDouble(Double_t &d)
Reads Double_t value from buffer.
virtual void ReadLong64(Long64_t &l)
Reads Long64_t value from buffer.
unsigned fJsonrCnt
! counter for all objects, used for referencing
Definition: TBufferJSON.h:315
Int_t fArrayCompact
! 0 - no array compression, 1 - exclude leading/trailing zeros, 2 - check value repetition
Definition: TBufferJSON.h:320
void JsonReadCollection(TCollection *obj, const TClass *objClass)
read content of ROOT collection
virtual void ReadStdString(std::string *s)
Reads a std::string.
virtual ~TBufferJSON()
destroy buffer
virtual void ReadUChar(UChar_t &c)
Reads UChar_t value from buffer.
void JsonPushValue()
If value exists, push in the current stack for post-processing.
virtual void ReadCharP(Char_t *c)
Reads array of characters from buffer.
virtual void ReadFastArray(Bool_t *b, Int_t n)
read array of Bool_t from buffer
virtual void ReadULong64(ULong64_t &l)
Reads ULong64_t value from buffer.
void SetTypenameTag(const char *tag="_typename")
Configures _typename tag in JSON structures By default "_typename" field in JSON structures used to s...
virtual void ReadInt(Int_t &i)
Reads Int_t value from buffer.
void JsonStartElement(const TStreamerElement *elem, const TClass *base_class)
Start new class member in JSON structures.
virtual void WriteULong64(ULong64_t l)
Writes ULong64_t value to buffer.
virtual void WriteTString(const TString &s)
Writes a TString.
Bool_t IsSkipClassInfo(const TClass *cl) const
Returns true if class info will be skipped from JSON.
virtual void WriteUChar(UChar_t c)
Writes UChar_t value to buffer.
virtual void WriteClass(const TClass *cl)
suppressed function of TBuffer
virtual void ReadBool(Bool_t &b)
Reads Bool_t value from buffer.
TString * fOutput
! current output buffer for json code
Definition: TBufferJSON.h:313
virtual void StreamObject(void *obj, const TClass *cl, const TClass *onFileClass=nullptr)
stream object to/from buffer
TString fTypeNameTag
! JSON member used for storing class name, when empty - no class name will be stored
Definition: TBufferJSON.h:323
static void * ConvertFromJSONAny(const char *str, TClass **cl=nullptr)
Read object from JSON, produced by ConvertToJSON() method.
@ kNoSpaces
no new lines plus remove all spaces around "," and ":" symbols
Definition: TBufferJSON.h:38
@ kMapAsObject
store std::map, std::unodered_map as JSON object
Definition: TBufferJSON.h:40
@ kSameSuppression
zero suppression plus compress many similar values together
Definition: TBufferJSON.h:44
virtual void ReadUShort(UShort_t &s)
Reads UShort_t value from buffer.
R__ALWAYS_INLINE void JsonWriteFastArray(const T *arr, Int_t arrsize, const char *typname, void(TBufferJSON::*method)(const T *, Int_t, const char *))
Template method to write array of arbitrary dimensions Different methods can be used for store last a...
TObjArray * fSkipClasses
! list of classes, which class info is not stored
Definition: TBufferJSON.h:325
virtual void ClassEnd(const TClass *)
Should be called at the end of custom streamer See TBufferJSON::ClassBegin for more details.
virtual void ReadBaseClass(void *start, TStreamerBase *elem)
Read data of base class.
virtual void ReadTString(TString &s)
Reads a TString.
static void * ConvertFromJSONChecked(const char *str, const TClass *expectedClass)
Read objects from JSON, one can reuse existing object.
virtual void WriteCharStar(char *s)
Writes a char*.
virtual void WriteULong(ULong_t l)
Writes ULong_t value to buffer.
virtual void WriteBool(Bool_t b)
Writes Bool_t value to buffer.
TString JsonWriteMember(const void *ptr, TDataMember *member, TClass *memberClass, Int_t arraylen)
Convert single data member to JSON structures Returns string with converted member.
virtual void ClassMember(const char *name, const char *typeName=nullptr, Int_t arrsize1=-1, Int_t arrsize2=-1)
Method indicates name and typename of class member, which should be now streamed in custom streamer F...
virtual void ReadChar(Char_t &c)
Reads Char_t value from buffer.
TString fArraySepar
! depending from compression level, ", " or ","
Definition: TBufferJSON.h:321
R__ALWAYS_INLINE void JsonReadFastArray(T *arr, Int_t arrsize, bool asstring=false)
Template method to read array from the JSON.
void SetSkipClassInfo(const TClass *cl)
Specify class which typename will not be stored in JSON Several classes can be configured To exclude ...
virtual void DecrementLevel(TVirtualStreamerInfo *)
Function is called from TStreamerInfo WriteBuffer and ReadBuffer functions and decrease level in json...
virtual void WriteCharP(const Char_t *c)
Writes array of characters to buffer.
virtual void WriteFastArray(const Bool_t *b, Int_t n)
Write array of Bool_t to buffer.
virtual void WriteFastArrayString(const Char_t *c, Int_t n)
Write array of Char_t to buffer.
void AppendOutput(const char *line0, const char *line1=nullptr)
Append two string to the output JSON, normally separate by line break.
TString fOutBuffer
! main output buffer for json code
Definition: TBufferJSON.h:312
TJSONStackObj * PopStack()
remove one level from stack
virtual void WriteArray(const Bool_t *b, Int_t n)
Write array of Bool_t to buffer.
virtual void ReadFloat(Float_t &f)
Reads Float_t value from buffer.
virtual void ReadCharStar(char *&s)
Reads a char* string.
TJSONStackObj * JsonStartObjectWrite(const TClass *obj_class, TStreamerInfo *info=nullptr)
Start object element with typeinfo.
virtual void ReadULong(ULong_t &l)
Reads ULong_t value from buffer.
Int_t JsonSpecialClass(const TClass *cl) const
return non-zero value when class has special handling in JSON it is TCollection (-130),...
virtual Int_t ReadStaticArray(Bool_t *b)
Read array of Bool_t from buffer.
virtual void WriteObjectClass(const void *actualObjStart, const TClass *actualClass, Bool_t cacheReuse)
Write object to buffer. Only used from TBuffer.
void SetCompact(int level)
Set level of space/newline/array compression Lower digit of compact parameter define formatting rules...
virtual void WriteShort(Short_t s)
Writes Short_t value to buffer.
Bool_t fMapAsObject
! when true, std::map will be converted into JSON object
Definition: TBufferJSON.h:318
virtual void * ReadObjectAny(const TClass *clCast)
Read object from buffer. Only used from TBuffer.
void JsonWriteConstChar(const char *value, Int_t len=-1, const char *=nullptr)
writes string value, processing all kind of special characters
virtual void IncrementLevel(TVirtualStreamerInfo *)
Function is called from TStreamerInfo WriteBuffer and ReadBuffer functions and indent new level in js...
void JsonReadTObjectMembers(TObject *obj, void *node=nullptr)
virtual TVirtualStreamerInfo * GetInfo()
Return current streamer info element.
virtual void SetStreamerElementNumber(TStreamerElement *elem, Int_t comp_type)
Function is called from TStreamerInfo WriteBuffer and ReadBuffer functions and add/verify next elemen...
void JsonWriteObject(const void *obj, const TClass *objClass, Bool_t check_map=kTRUE)
Write object to buffer If object was written before, only pointer will be stored If check_map==kFALSE...
virtual void SkipObjectAny()
Skip any kind of object from buffer.
void * JsonReadObject(void *obj, const TClass *objClass=nullptr, TClass **readClass=nullptr)
Read object from current JSON node.
void WorkWithClass(TStreamerInfo *info, const TClass *cl=nullptr)
Prepares buffer to stream data of specified class.
virtual void WriteFloat(Float_t f)
Writes Float_t value to buffer.
R__ALWAYS_INLINE void JsonReadBasic(T &value)
Template function to read basic value from JSON.
virtual void WriteLong(Long_t l)
Writes Long_t value to buffer.
Base class for text-based streamers like TBufferJSON or TBufferXML Special actions list will use meth...
Definition: TBufferText.h:21
static const char * ConvertFloat(Float_t v, char *buf, unsigned len, Bool_t not_optimize=kFALSE)
convert float to string with configured format
static const char * ConvertDouble(Double_t v, char *buf, unsigned len, Bool_t not_optimize=kFALSE)
convert float to string with configured format
virtual void ReadBaseClass(void *start, TStreamerBase *elem)
Read data of base class.
@ kRead
Definition: TBuffer.h:72
Bool_t IsWriting() const
Definition: TBuffer.h:86
Bool_t IsReading() const
Definition: TBuffer.h:85
TClass instances represent classes, structs and namespaces in the ROOT type system.
Definition: TClass.h:75
ROOT::ESTLType GetCollectionType() const
Return the 'type' of the STL the TClass is representing.
Definition: TClass.cxx:2813
void * New(ENewType defConstructor=kClassNew, Bool_t quiet=kFALSE) const
Return a pointer to a newly allocated object of this class.
Definition: TClass.cxx:4841
void Destructor(void *obj, Bool_t dtorOnly=kFALSE)
Explicitly call destructor for object.
Definition: TClass.cxx:5198
TList * GetListOfRealData() const
Definition: TClass.h:423
Int_t Size() const
Return size of object of this class.
Definition: TClass.cxx:5483
Bool_t IsTObject() const
Return kTRUE is the class inherits from TObject.
Definition: TClass.cxx:5717
Int_t GetBaseClassOffset(const TClass *toBase, void *address=0, bool isDerivedObject=true)
Definition: TClass.cxx:2718
TVirtualCollectionProxy * GetCollectionProxy() const
Return the proxy describing the collection (if any).
Definition: TClass.cxx:2824
void Streamer(void *obj, TBuffer &b, const TClass *onfile_class=0) const
Definition: TClass.h:568
Version_t GetClassVersion() const
Definition: TClass.h:391
TClass * GetActualClass(const void *object) const
Return a pointer the the real class of the object.
Definition: TClass.cxx:2535
TRealData * GetRealData(const char *name) const
Return pointer to TRealData element with name "name".
Definition: TClass.cxx:3352
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
An array of clone (identical) objects.
Definition: TClonesArray.h:32
TClass * GetClass() const
Definition: TClonesArray.h:56
void SetClass(const char *classname, Int_t size=1000)
see TClonesArray::SetClass(const TClass*)
TObject * ConstructedAt(Int_t idx)
Get an object at index 'idx' that is guaranteed to have been constructed.
Collection abstract base class.
Definition: TCollection.h:63
virtual const char * GetName() const
Return name of this collection.
void SetName(const char *name)
Definition: TCollection.h:204
virtual void Add(TObject *obj)=0
virtual Int_t GetSize() const
Return the capacity of the collection, i.e.
Definition: TCollection.h:182
All ROOT classes may have RTTI (run time type identification) support added.
Definition: TDataMember.h:31
Int_t GetMaxIndex(Int_t dim) const
Return maximum index for array dimension "dim".
const char * GetTrueTypeName() const
Get full type description of data member, e,g.: "class TDirectory*".
Int_t GetArrayDim() const
Return number of array dimensions.
Int_t GetUnitSize() const
Get the sizeof the underlying type of the data member (i.e.
Bool_t IsBasic() const
Return true if data member is a basic type, e.g. char, int, long...
Int_t IsSTLContainer()
The return type is defined in TDictionary (kVector, kList, etc.)
Bool_t IsaPointer() const
Return true if data member is a pointer.
TDataType * GetDataType() const
Definition: TDataMember.h:74
const char * GetTypeName() const
Get type of data member, e,g.: "class TDirectory*" -> "TDirectory".
const char * GetArrayIndex() const
If the data member is pointer and has a valid array size in its comments GetArrayIndex returns a stri...
Basic data type descriptor (datatype information is obtained from CINT).
Definition: TDataType.h:44
Int_t GetType() const
Definition: TDataType.h:68
Option_t * GetOption() const
Definition: TCollection.h:251
A doubly linked list.
Definition: TList.h:44
virtual void Add(TObject *obj)
Definition: TList.h:87
TMap implements an associative array of (key,value) pairs using a THashTable for efficient retrieval ...
Definition: TMap.h:40
void Add(TObject *obj)
This function may not be used (but we need to provide it since it is a pure virtual in TCollection).
Definition: TMap.cxx:53
TObject * GetValue(const char *keyname) const
Returns a pointer to the value associated with keyname as name of the key.
Definition: TMap.cxx:235
virtual const char * GetName() const
Returns name of object.
Definition: TNamed.h:47
An array of TObjects.
Definition: TObjArray.h:37
Int_t IndexOf(const TObject *obj) const
Definition: TObjArray.cxx:604
void Add(TObject *obj)
Definition: TObjArray.h:74
virtual TObject * FindObject(const char *name) const
Find an object in this collection using its name.
Definition: TObjArray.cxx:414
Mother of all ROOT objects.
Definition: TObject.h:37
R__ALWAYS_INLINE Bool_t TestBit(UInt_t f) const
Definition: TObject.h:172
virtual void Warning(const char *method, const char *msgfmt,...) const
Issue warning message.
Definition: TObject.cxx:866
void SetBit(UInt_t f, Bool_t set)
Set or unset the user status bits as specified in f.
Definition: TObject.cxx:694
virtual Bool_t InheritsFrom(const char *classname) const
Returns kTRUE if object inherits from class "classname".
Definition: TObject.cxx:443
virtual void Error(const char *method, const char *msgfmt,...) const
Issue error message.
Definition: TObject.cxx:880
virtual void SetUniqueID(UInt_t uid)
Set the unique object id.
Definition: TObject.cxx:705
@ kMustCleanup
if object destructor must call RecursiveRemove()
Definition: TObject.h:60
virtual void Info(const char *method, const char *msgfmt,...) const
Issue info message.
Definition: TObject.cxx:854
The TRealData class manages the effective list of all data members for a given class.
Definition: TRealData.h:30
TDataMember * GetDataMember() const
Definition: TRealData.h:53
Long_t GetThisOffset() const
Definition: TRealData.h:55
virtual TClass * GetClassPointer() const
Returns a pointer to the TClass of this element.
Int_t GetType() const
virtual TClass * GetClassPointer() const
Returns a pointer to the TClass of this element.
virtual void SetArrayDim(Int_t dim)
Set number of array dimensions.
Int_t GetArrayDim() const
Int_t GetArrayLength() const
Int_t GetMaxIndex(Int_t i) const
const char * GetTypeName() const
virtual Bool_t IsBase() const
Return kTRUE if the element represent a base class.
virtual void SetMaxIndex(Int_t dim, Int_t max)
set maximum index for array with dimension dim
Describe Streamer information for one class version.
Definition: TStreamerInfo.h:43
TObjArray * GetElements() const
TClass * GetClass() const
Int_t GetClassVersion() const
Basic string class.
Definition: TString.h:131
Ssiz_t Length() const
Definition: TString.h:405
Int_t Atoi() const
Return integer value of string.
Definition: TString.cxx:1921
void Clear()
Clear string without changing its capacity.
Definition: TString.cxx:1176
TString & Replace(Ssiz_t pos, Ssiz_t n, const char *s)
Definition: TString.h:677
const char * Data() const
Definition: TString.h:364
Ssiz_t Capacity() const
Definition: TString.h:352
void Resize(Ssiz_t n)
Resize the string. Truncate or add blanks as necessary.
Definition: TString.cxx:1095
TString & Append(const char *cs)
Definition: TString.h:559
static TString Format(const char *fmt,...)
Static method which formats a string using a printf style format descriptor and return a TString.
Definition: TString.cxx:2311
void Form(const char *fmt,...)
Formats a string using a printf style format descriptor.
Definition: TString.cxx:2289
Ssiz_t Index(const char *pat, Ssiz_t i=0, ECaseCompare cmp=kExact) const
Definition: TString.h:634
Abstract Interface class describing Streamer information for one class.
static Bool_t CanDelete()
static function returning true if ReadBuffer can delete object
virtual TClass * GetClass() const =0
const Int_t n
Definition: legend1.C:16
double T(double x)
Definition: ChebyshevPol.h:34
@ kSTLend
Definition: ESTLType.h:46
@ kSTLvector
Definition: ESTLType.h:30
@ kSTLlist
Definition: ESTLType.h:31
@ kSTLforwardlist
Definition: ESTLType.h:41
@ kNotSTL
Definition: ESTLType.h:29
@ kUnorderedMultiSet
Definition: TClassEdit.h:103
@ kUnorderedMultiMap
Definition: TClassEdit.h:105
@ kForwardlist
Definition: TClassEdit.h:96
bool IsStdClass(const char *type)
return true if the class belongs to the std namespace
static constexpr double s
Definition: first.py:1
const char * cnt
Definition: TXMLSetup.cxx:74
auto * l
Definition: textangle.C:4