GRSISort "v4.0.0.5"
An extension of the ROOT analysis Framework
Loading...
Searching...
No Matches
TSingleton.h
Go to the documentation of this file.
1#ifndef TSINGLETON_H
2#define TSINGLETON_H
3
4#include <iostream>
5
6#include "TObject.h"
7#include "TDirectory.h"
8#include "TFile.h"
9#include "TList.h"
10#include "TKey.h"
11
12#include "Globals.h"
13
14/** \addtogroup Sorting
15 * * @{
16 * */
17
18///////////////////////////////////////////////////////////////
19///
20/// This class is intended as a base class for singletons,
21/// especially those that are written to file.
22/// The Get() function is written such that it reads the class
23/// from file if needed. This is the case if it hasn't been
24/// read yet, or if the gDirectory has been changed.
25/// This means in a loop over different input files, Get() will
26/// always return the info of the current file.
27///
28///////////////////////////////////////////////////////////////
29
30template <class T>
31class TSingleton : public TObject { // NOLINT(cppcoreguidelines-virtual-class-destructor)
32public:
33 static T* Get(bool verbose = false)
34 {
35 // if we don't have an instance yet or changed into another directory
36 // we want to read from the current directory
37 if(fSingleton == nullptr || fDir != gDirectory) {
38 if((gDirectory->GetFile()) != nullptr) {
39 TList* list = gDirectory->GetFile()->GetListOfKeys();
40 TIter iter(list);
41 if(verbose) { std::cout << "Reading " << T::Class()->GetName() << R"( from file ")" << CYAN << gDirectory->GetFile()->GetName() << RESET_COLOR << R"(")" << std::endl; }
42 while(TKey* key = static_cast<TKey*>(iter.Next())) {
43 if(strcmp(key->GetClassName(), T::Class()->GetName()) != 0) {
44 continue;
45 }
46 // we found the object in the file, so we use it as our singleton
47 // this automatically deletes the old singleton if we just switched files
48 Set(static_cast<T*>(key->ReadObj()));
49 fDir = gDirectory; // in either case (read from file or created new), gDirectory is the current directory
50 break; // we will find the newest key first, so we want to break here and not try and read other instaces of the same class
51 }
52 } else if(verbose) {
53 std::cout << "Not reading " << T::Class()->GetName() << " from file!" << std::endl;
54 }
55 if(fSingleton == nullptr) {
56 fSingleton = new T;
57 fDir = gDirectory; // in either case (read from file or created new), gDirectory is the current directory
58 if(verbose) { std::cout << "Created new singleton of class " << T::Class()->GetName() << std::endl; }
59 }
60 } else if(verbose) {
61 std::cout << "Re-using old singleton of class " << T::Class()->GetName() << std::endl;
62 }
63 return fSingleton;
64 }
65
66 static T* GetAll()
67 {
68 // get the singleton itself
69 Get();
70 // check if we can get the run number and sub-run number from the directory we read this from
71 std::string fileName = fDir->GetName();
72 std::string filebase;
73 // we expect the root-file name format to be (<dir>/)<base><5 digit run number>_<3 digit subrun number>.root
74 // so the length needs to be at least 9 (assuming single character for base, run, and subrun number)
75 if(fileName.length() < 9) {
76 return fSingleton;
77 }
78 size_t underscore = fileName.find_last_of('_');
79 size_t dot = fileName.find_last_of('.');
80 // check that the dot is length minus 5 (which also ensures it was found) and
81 // that the underscore is dot minus 4 (again ensuring it was found)
82 if(dot != fileName.length() - 5 || underscore != dot - 4) {
83 return fSingleton;
84 }
85 filebase = fileName.substr(0, underscore - 5);
86 int runNumber = atoi(fileName.substr(underscore - 5).c_str());
87 int subrunNumber = atoi(fileName.substr(dot - 3).c_str());
88 if(runNumber > 0 || subrunNumber > 0) {
89 TFile* prevSubRun = nullptr;
90 if(subrunNumber > 0) {
91 prevSubRun = new TFile(Form("%s%05d_%03d.root", filebase.c_str(), runNumber, subrunNumber - 1));
92 } else {
93 // search for last subrun of previous run
94 int subrun = 0;
95 prevSubRun = new TFile(Form("%s%05d_%03d.root", filebase.c_str(), runNumber - 1, subrun++));
96 TFile* tmpFile = nullptr;
97 while(prevSubRun != nullptr && prevSubRun->IsOpen()) {
98 if(tmpFile != nullptr) {
99 tmpFile->Close();
100 tmpFile = prevSubRun;
101 }
102 prevSubRun = new TFile(Form("%s%05d_%03d.root", filebase.c_str(), runNumber - 1, subrun++));
103 }
104 // this works if we found a subrun (i.e. the last read is not good, but the one stored in tmp is)
105 // of if we didn't find one (i.e. tmpFile is a nullptr which we check for)
106 prevSubRun = tmpFile;
107 }
108 if(prevSubRun != nullptr && prevSubRun->IsOpen()) {
109 T* prevSingleton = static_cast<T*>(prevSubRun->Get(fSingleton->GetName()));
110 if(prevSingleton != nullptr) {
111 fSingleton->Add(prevSingleton);
112 std::cout << "Found previous " << fSingleton->GetName() << " data from " << prevSubRun->GetName() << std::endl;
113 } else {
114 std::cout << "Failed to find previous " << fSingleton->GetName() << " data from " << prevSubRun->GetName() << std::endl;
115 // try to find object without leading T
116 prevSingleton = static_cast<T*>(prevSubRun->Get(&(fSingleton->GetName()[1])));
117 if(prevSingleton != nullptr) {
118 fSingleton->Add(prevSingleton);
119 std::cout << "Found previous " << &(fSingleton->GetName()[1]) << " data from " << prevSubRun->GetName() << std::endl;
120 } else {
121 std::cout << "Failed to find previous " << &(fSingleton->GetName()[1]) << " data from " << prevSubRun->GetName() << std::endl;
122 }
123 }
124 prevSubRun->Close();
125 fDir->cd();
126 } else {
127 std::cout << "Failed to find previous file " << prevSubRun->GetName() << " not adding data to " << fSingleton->GetName() << std::endl;
128 }
129 }
130 return fSingleton;
131 }
132
133 static void Set(T* val)
134 {
135 if(fSingleton != val) {
136 delete fSingleton;
137 fSingleton = val;
138 }
139 }
140
141 static T* AddCurrent()
142 {
143 // if we don't have an instance yet, we just use Get
144 if(fSingleton == nullptr) {
145 return Get();
146 }
147 // if we changed into another directory we want to add the object read from the current directory
148 if(fDir != gDirectory) {
149 if((gDirectory->GetFile()) != nullptr) {
150 TList* list = gDirectory->GetFile()->GetListOfKeys();
151 TIter iter(list);
152 std::cout << R"(Reading from file ")" << CYAN << gDirectory->GetFile()->GetName() << RESET_COLOR << R"(": )" << std::flush;
153 while(TKey* key = static_cast<TKey*>(iter.Next())) {
154 if(strcmp(key->GetClassName(), T::Class()->GetName()) != 0) {
155 continue;
156 }
157 // we found the object in the file, so we use it as our singleton
158 // this automatically deletes the old singleton if we just switched files
159 std::cout << "adding " << T::Class()->GetName() << " " << std::flush;
160 T* tmpSingleton = static_cast<T*>(key->ReadObj());
161 fSingleton->Add(tmpSingleton);
162 fDir = gDirectory; // update the directory to gDirectory so we don't read from this file again
163 }
164 std::cout << std::endl;
165 }
166 }
167 return fSingleton;
168 }
169
170 static void PrintDirectory()
171 {
172 std::cout << "Singleton " << fSingleton << " was read from " << (fDir != nullptr ? fDir->GetName() : "N/A") << std::endl;
173 }
174
175protected:
176 TSingleton() = default;
177 TSingleton(const TSingleton&) = default;
178 TSingleton(TSingleton&&) noexcept = default;
179 TSingleton& operator=(const TSingleton&) = default;
180 TSingleton& operator=(TSingleton&&) noexcept = default;
181 // seems like clang-tidy thinks this destructor is protected and virtual?
182 ~TSingleton() = default; // NOLINT(cppcoreguidelines-virtual-class-destructor)
183
184private:
185 static T* fSingleton;
186 static TDirectory* fDir;
187
188 /// \cond CLASSIMP
189 ClassDef(TSingleton, 1) // NOLINT(readability-else-after-return)
190 /// \endcond
191};
192
193/// \cond CLASSIMP
194templateClassImp(TSingleton)
195/// \endcond
196
197template <class T>
198T* TSingleton<T>::fSingleton = nullptr;
199
200template <class T>
201TDirectory* TSingleton<T>::fDir = nullptr;
202
203template <class T>
204void TSingleton<T>::Streamer(TBuffer& R__b)
205{
206 /// Stream an object of class T.
207 if(R__b.IsReading()) {
208 // R__b.ReadClassBuffer(T::Class(), &(Get()));
209 // Set(static_cast<T*>(this));
210 } else {
211 // R__b.WriteClassBuffer(T::Class(), &(Get()));
212 }
213}
214
215template <class T>
216TClass* TSingleton<T>::Class()
217{
218 return T::Class();
219}
220/*! @} */
221#endif
#define CYAN
Definition Globals.h:12
#define RESET_COLOR
Definition Globals.h:5
TSingleton(const TSingleton &)=default
static T * AddCurrent()
Definition TSingleton.h:141
static void PrintDirectory()
Definition TSingleton.h:170
static T * Get(bool verbose=false)
Definition TSingleton.h:33
TSingleton(TSingleton &&) noexcept=default
static T * GetAll()
Definition TSingleton.h:66
TSingleton()=default
static void Set(T *val)
Definition TSingleton.h:133
static T * fSingleton
Definition TSingleton.h:185
static TDirectory * fDir
Definition TSingleton.h:186