File indexing completed on 2026-10-30 08:33:58
0001 #ifndef LFHCAL_CHECKED_IO_H
0002 #define LFHCAL_CHECKED_IO_H
0003
0004 #include "TError.h"
0005 #include "TFile.h"
0006 #include <atomic>
0007 #include <cstring>
0008 #include <exception>
0009 #include <initializer_list>
0010 #include <iostream>
0011
0012 namespace lfhcal {
0013
0014
0015
0016 class RootIOErrors {
0017 public:
0018 RootIOErrors() {
0019 failed().store(false);
0020 previous() = SetErrorHandler(Handle);
0021 }
0022 ~RootIOErrors() { SetErrorHandler(previous()); }
0023 RootIOErrors(const RootIOErrors&) = delete;
0024 RootIOErrors& operator=(const RootIOErrors&) = delete;
0025 bool ok() const { return !failed().load(); }
0026
0027 private:
0028 static std::atomic<bool>& failed() {
0029 static std::atomic<bool> value{false};
0030 return value;
0031 }
0032 static ErrorHandlerFunc_t& previous() {
0033 static ErrorHandlerFunc_t value = nullptr;
0034 return value;
0035 }
0036 static bool IsIOError(int level, const char* location) {
0037 if (level < kError || !location) return false;
0038 const char* prefixes[] = {"TFile::", "TDirectory", "TBranch", "TTree::",
0039 "TBufferFile::", "TKey::", "TASImage::", "TImage::", "TCanvas::",
0040 "TPad::", "TPDF::", "TPostScript::", "TSVG::"};
0041 for (const char* prefix : prefixes)
0042 if (std::strncmp(location, prefix, std::strlen(prefix)) == 0) return true;
0043 return false;
0044 }
0045 static void Handle(int level, Bool_t abort, const char* location, const char* message) {
0046 if (IsIOError(level, location)) failed().store(true);
0047 ErrorHandlerFunc_t handler = previous();
0048 if (handler && handler != Handle) handler(level, abort, location, message);
0049 else DefaultErrorHandler(level, abort, location, message);
0050 }
0051 };
0052
0053 inline bool CloseAndCheckOutputs(std::initializer_list<TFile*> outputs) {
0054 bool ok = true;
0055 for (TFile* output : outputs) {
0056 if (!output) continue;
0057 if (output->IsOpen()) {
0058 output->Flush();
0059 output->Close();
0060 }
0061 if (output->IsZombie() || output->TestBit(TFile::kWriteError)) {
0062 std::cerr << "ROOT output failed: " << output->GetName() << std::endl;
0063 ok = false;
0064 }
0065 }
0066 return ok;
0067 }
0068
0069
0070
0071 template <class Analysis>
0072 int RunCheckedAnalysis(Analysis& analysis, const char* executable) {
0073 RootIOErrors io;
0074 try {
0075 if (!analysis.CheckAndOpenIO()) {
0076 std::cerr << executable << ": input/configuration check failed" << std::endl;
0077 return 1;
0078 }
0079 const bool processed = analysis.Process();
0080 const bool written = CloseAndCheckOutputs(
0081 {analysis.RootOutput, analysis.RootOutputHist, analysis.RootCalibOutput});
0082 if (!processed || !written || !io.ok()) {
0083 std::cerr << executable << ": processing or I/O failed" << std::endl;
0084 return 1;
0085 }
0086 } catch (const std::exception& error) {
0087 std::cerr << executable << ": processing or I/O failed: " << error.what() << std::endl;
0088 return 1;
0089 }
0090 std::cout << "Exiting" << std::endl;
0091 return 0;
0092 }
0093
0094 }
0095 #endif