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 do have an instance and changed into another directory
148 // we want to add the object read from the current directory
149 if(fSingleton != nullptr && fDir != gDirectory) {
150 if((gDirectory->GetFile()) != nullptr) {
151 TList* list = gDirectory->GetFile()->GetListOfKeys();
152 TIter iter(list);
153 std::cout << R"(Reading from file ")" << CYAN << gDirectory->GetFile()->GetName() << RESET_COLOR << R"(": )" << std::flush;
154 while(TKey* key = static_cast<TKey*>(iter.Next())) {
155 if(strcmp(key->GetClassName(), T::Class()->GetName()) != 0) {
156 continue;
157 }
158 // we found the object in the file, so we use it as our singleton
159 // this automatically deletes the old singleton if we just switched files
160 std::cout << "adding " << T::Class()->GetName() << " " << std::flush;
161 T* tmpSingleton = static_cast<T*>(key->ReadObj());
162 fSingleton->Add(tmpSingleton);
163 fDir = gDirectory; // update the directory to gDirectory so we don't read from this file again
164 }
165 std::cout << std::endl;
166 }
167 }
168 return fSingleton;
169 }
170
171 static void PrintDirectory()
172 {
173 std::cout << "Singleton " << fSingleton << " was read from " << (fDir != nullptr ? fDir->GetName() : "N/A") << std::endl;
174 }
175
176protected:
177 TSingleton() = default;
178 TSingleton(const TSingleton&) = default;
179 TSingleton(TSingleton&&) noexcept = default;
180 TSingleton& operator=(const TSingleton&) = default;
181 TSingleton& operator=(TSingleton&&) noexcept = default;
182 // seems like clang-tidy thinks this destructor is protected and virtual?
183 ~TSingleton() = default; // NOLINT(cppcoreguidelines-virtual-class-destructor)
184
185private:
186 static T* fSingleton;
187 static TDirectory* fDir;
188
189 /// \cond CLASSIMP
190 ClassDef(TSingleton, 1) // NOLINT(readability-else-after-return)
191 /// \endcond
192};
193
194/// \cond CLASSIMP
195templateClassImp(TSingleton)
196/// \endcond
197
198template <class T>
199T* TSingleton<T>::fSingleton = nullptr;
200
201template <class T>
202TDirectory* TSingleton<T>::fDir = nullptr;
203
204template <class T>
205void TSingleton<T>::Streamer(TBuffer& R__b)
206{
207 /// Stream an object of class T.
208 if(R__b.IsReading()) {
209 // R__b.ReadClassBuffer(T::Class(), &(Get()));
210 // Set(static_cast<T*>(this));
211 } else {
212 // R__b.WriteClassBuffer(T::Class(), &(Get()));
213 }
214}
215
216template <class T>
217TClass* TSingleton<T>::Class()
218{
219 return T::Class();
220}
221/*! @} */
222#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:171
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:186
static TDirectory * fDir
Definition TSingleton.h:187