File indexing completed on 2025-02-21 09:58:12
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027 #pragma once
0028
0029 #include <array>
0030 #include <stdexcept>
0031 #include <string>
0032 #include <tuple>
0033 #include <type_traits>
0034
0035 #include <TFile.h>
0036 #include <TTree.h>
0037
0038 namespace dfe {
0039
0040
0041 template<typename NamedTuple>
0042 class NamedTupleRootWriter {
0043 public:
0044 NamedTupleRootWriter() = delete;
0045 NamedTupleRootWriter(const NamedTupleRootWriter&) = delete;
0046 NamedTupleRootWriter(NamedTupleRootWriter&&) = delete;
0047 NamedTupleRootWriter& operator=(const NamedTupleRootWriter&) = delete;
0048 NamedTupleRootWriter& operator=(NamedTupleRootWriter&&) = delete;
0049
0050
0051
0052
0053
0054 NamedTupleRootWriter(const std::string& path, const std::string& tree_name);
0055
0056
0057
0058
0059
0060
0061
0062 NamedTupleRootWriter(TDirectory* dir, const std::string& tree_name);
0063
0064 ~NamedTupleRootWriter();
0065
0066
0067 void append(const NamedTuple& record);
0068
0069 private:
0070
0071 using Tuple = typename NamedTuple::Tuple;
0072
0073 TFile* m_file;
0074 TTree* m_tree;
0075 Tuple m_data;
0076
0077 template<std::size_t... I>
0078 void setup_branches(std::index_sequence<I...>);
0079 };
0080
0081
0082 template<typename NamedTuple>
0083 class NamedTupleRootReader {
0084 public:
0085 NamedTupleRootReader() = delete;
0086 NamedTupleRootReader(const NamedTupleRootReader&) = delete;
0087 NamedTupleRootReader(NamedTupleRootReader&&) = delete;
0088 NamedTupleRootReader& operator=(const NamedTupleRootReader&) = delete;
0089 NamedTupleRootReader& operator=(NamedTupleRootReader&&) = delete;
0090
0091
0092
0093
0094
0095 NamedTupleRootReader(const std::string& path, const std::string& tree_name);
0096
0097
0098
0099
0100
0101
0102
0103 NamedTupleRootReader(TDirectory* dir, const std::string& tree_name);
0104
0105 ~NamedTupleRootReader();
0106
0107
0108
0109
0110
0111 bool read(NamedTuple& record);
0112
0113 private:
0114
0115 using Tuple = typename NamedTuple::Tuple;
0116
0117 TFile* m_file;
0118 TTree* m_tree;
0119 int64_t m_next;
0120 Tuple m_data;
0121
0122 template<std::size_t... I>
0123 void setup_branches(std::index_sequence<I...>);
0124 };
0125
0126
0127
0128 template<typename NamedTuple>
0129 inline NamedTupleRootWriter<NamedTuple>::NamedTupleRootWriter(
0130 const std::string& path, const std::string& tree_name)
0131 : m_file(new TFile(path.c_str(), "RECREATE"))
0132 , m_tree(new TTree(tree_name.c_str(), "", 99, m_file)) {
0133 if (not m_file) {
0134 throw std::runtime_error("Could not create file");
0135 }
0136 if (not m_file->IsOpen()) {
0137 throw std::runtime_error("Could not open file");
0138 }
0139 if (not m_tree) {
0140 throw std::runtime_error("Could not create tree");
0141 }
0142 setup_branches(std::make_index_sequence<std::tuple_size<Tuple>::value>());
0143 }
0144
0145 template<typename NamedTuple>
0146 inline NamedTupleRootWriter<NamedTuple>::NamedTupleRootWriter(
0147 TDirectory* dir, const std::string& tree_name)
0148 : m_file(nullptr)
0149 , m_tree(new TTree(tree_name.c_str(), "", 99, dir)) {
0150 if (not dir) {
0151 throw std::runtime_error("Invalid output directory given");
0152 }
0153 if (not m_tree) {
0154 throw std::runtime_error("Could not create tree");
0155 }
0156 setup_branches(std::make_index_sequence<std::tuple_size<Tuple>::value>());
0157 }
0158
0159 namespace namedtuple_root_impl {
0160
0161
0162 template<typename T, typename Enable = void>
0163 struct TypeCode;
0164
0165 template<char Code>
0166 struct TypeCodePlainImpl {
0167 static constexpr char value = Code;
0168 };
0169 template<>
0170 struct TypeCode<bool> : TypeCodePlainImpl<'O'> {};
0171 template<>
0172 struct TypeCode<float> : TypeCodePlainImpl<'F'> {};
0173 template<>
0174 struct TypeCode<double> : TypeCodePlainImpl<'D'> {};
0175
0176
0177
0178
0179
0180 template<typename T, char Unsigned, char Signed>
0181 struct TypeCodeIntImpl {
0182 static constexpr char value = std::is_unsigned<T>::value ? Unsigned : Signed;
0183 };
0184 template<typename T, std::size_t S>
0185 constexpr bool is_integer_with_size_v = std::is_integral<T>::value
0186 and (sizeof(T) == S);
0187 template<typename T>
0188 struct TypeCode<T, typename std::enable_if_t<is_integer_with_size_v<T, 1>>>
0189 : TypeCodeIntImpl<T, 'b', 'B'> {};
0190 template<typename T>
0191 struct TypeCode<T, typename std::enable_if_t<is_integer_with_size_v<T, 2>>>
0192 : TypeCodeIntImpl<T, 's', 'S'> {};
0193 template<typename T>
0194 struct TypeCode<T, typename std::enable_if_t<is_integer_with_size_v<T, 4>>>
0195 : TypeCodeIntImpl<T, 'i', 'I'> {};
0196 template<typename T>
0197 struct TypeCode<T, typename std::enable_if_t<is_integer_with_size_v<T, 8>>>
0198 : TypeCodeIntImpl<T, 'l', 'L'> {};
0199
0200 }
0201
0202 template<typename NamedTuple>
0203 template<std::size_t... I>
0204 inline void
0205 NamedTupleRootWriter<NamedTuple>::setup_branches(std::index_sequence<I...>) {
0206 static_assert(
0207 sizeof...(I) == std::tuple_size<Tuple>::value, "Something is very wrong");
0208
0209
0210 std::array<std::string, sizeof...(I)> names = NamedTuple::names();
0211 std::array<std::string, sizeof...(I)> leafs = {
0212 (names[I] + '/'
0213 + namedtuple_root_impl::TypeCode<
0214 std::tuple_element_t<I, Tuple>>::value)...};
0215
0216
0217
0218
0219
0220 (void)std::array<TBranch*, sizeof...(I)>{m_tree->Branch(
0221 names[I].c_str(), &std::get<I>(m_data), leafs[I].c_str())...};
0222 }
0223
0224 template<typename NamedTuple>
0225 inline NamedTupleRootWriter<NamedTuple>::~NamedTupleRootWriter() {
0226
0227 if (m_tree) {
0228 m_tree->Write(nullptr, TObject::kOverwrite);
0229 }
0230
0231 if (m_file) {
0232 m_file->Close();
0233 delete m_file;
0234 }
0235 }
0236
0237 template<typename NamedTuple>
0238 inline void
0239 NamedTupleRootWriter<NamedTuple>::append(const NamedTuple& record) {
0240 m_data = record;
0241 if (m_tree->Fill() == -1) {
0242 throw std::runtime_error("Could not fill an entry");
0243 }
0244 }
0245
0246
0247
0248 template<typename NamedTuple>
0249 inline NamedTupleRootReader<NamedTuple>::NamedTupleRootReader(
0250 const std::string& path, const std::string& tree_name)
0251 : m_file(new TFile(path.c_str(), "READ")), m_tree(nullptr), m_next(0) {
0252 if (not m_file) {
0253 throw std::runtime_error("Could not open file");
0254 }
0255 if (not m_file->IsOpen()) {
0256 throw std::runtime_error("Could not open file");
0257 }
0258 m_tree = static_cast<TTree*>(m_file->Get(tree_name.c_str()));
0259 if (not m_tree) {
0260 throw std::runtime_error("Could not read tree");
0261 }
0262 setup_branches(std::make_index_sequence<std::tuple_size<Tuple>::value>());
0263 }
0264
0265 template<typename NamedTuple>
0266 inline NamedTupleRootReader<NamedTuple>::NamedTupleRootReader(
0267 TDirectory* dir, const std::string& tree_name)
0268 : m_file(nullptr)
0269 , m_tree(nullptr)
0270 , m_next(0) {
0271 if (not dir) {
0272 throw std::runtime_error("Invalid input directory given");
0273 }
0274 m_tree = static_cast<TTree*>(dir->Get(tree_name.c_str()));
0275 if (not m_tree) {
0276 throw std::runtime_error("Could not read tree");
0277 }
0278 setup_branches(std::make_index_sequence<std::tuple_size<Tuple>::value>());
0279 }
0280
0281 namespace io_root_impl {
0282
0283
0284
0285 __attribute__((unused)) inline ULong64_t*
0286 get_address(uint64_t& x) {
0287 static_assert(
0288 sizeof(ULong64_t) == sizeof(uint64_t), "Inconsistent type sizes");
0289 return reinterpret_cast<ULong64_t*>(&x);
0290 }
0291 __attribute__((unused)) inline char*
0292 get_address(int8_t& x) {
0293 static_assert(sizeof(char) == sizeof(int8_t), "Inconsistent type sizes");
0294 return reinterpret_cast<char*>(&x);
0295 }
0296 __attribute__((unused)) inline Long64_t*
0297 get_address(int64_t& x) {
0298 static_assert(sizeof(Long64_t) == sizeof(int64_t), "Inconsistent type sizes");
0299 return reinterpret_cast<Long64_t*>(&x);
0300 }
0301 template<typename T>
0302 inline T*
0303 get_address(T& x) {
0304 return &x;
0305 }
0306
0307 }
0308
0309 template<typename NamedTuple>
0310 template<std::size_t... I>
0311 inline void
0312 NamedTupleRootReader<NamedTuple>::setup_branches(std::index_sequence<I...>) {
0313 static_assert(
0314 sizeof...(I) == std::tuple_size<Tuple>::value, "Something is very wrong");
0315
0316 using std::get;
0317
0318
0319 std::array<std::string, sizeof...(I)> names = NamedTuple::names();
0320
0321 (void)std::array<Int_t, sizeof...(I)>{m_tree->SetBranchAddress(
0322 names[I].c_str(), io_root_impl::get_address(get<I>(m_data)))...};
0323 }
0324
0325 template<typename NamedTuple>
0326 inline NamedTupleRootReader<NamedTuple>::~NamedTupleRootReader() {
0327
0328 if (m_file) {
0329 m_file->Close();
0330 delete m_file;
0331 }
0332 }
0333
0334 template<typename NamedTuple>
0335 inline bool
0336 NamedTupleRootReader<NamedTuple>::read(NamedTuple& record) {
0337 auto ret = m_tree->GetEntry(m_next);
0338
0339 if (ret < 0) {
0340 throw std::runtime_error("Could not read entry");
0341 }
0342
0343 if (ret == 0) {
0344 return false;
0345 }
0346
0347 record = m_data;
0348 m_next += 1;
0349 return true;
0350 }
0351
0352 }