Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2025-04-19 09:13:41

0001 // -*- C++ -*-
0002 //
0003 // This file is part of YODA -- Yet more Objects for Data Analysis
0004 // Copyright (C) 2008-2024 The YODA collaboration (see AUTHORS for details)
0005 //
0006 #ifndef YODA_READER_H
0007 #define YODA_READER_H
0008 
0009 #include "YODA/Utils/ReaderUtils.h"
0010 #include "YODA/Utils/Traits.h"
0011 #include <memory>
0012 #include <fstream>
0013 #include <iostream>
0014 #include <sstream>
0015 #include <type_traits>
0016 #include <unordered_map>
0017 #include <vector>
0018 
0019 namespace YODA {
0020 
0021 
0022   /// Pure virtual base class for various output writers.
0023   class Reader {
0024 
0025   public:
0026 
0027     /// Convenience alias for AO Reader
0028     using TypeRegisterItr = typename std::unordered_map<std::string, std::unique_ptr<AOReaderBase>>::const_iterator;
0029 
0030     /// Virtual destructor
0031     virtual ~Reader() {
0032       // This is technically leaking memory, but since this
0033       // is a (static) singleton, there should be no issue.
0034       // Cython relies on it for data-structure alignment, too.
0035       for (auto& aor : _register) { aor.second.release(); }
0036     }
0037 
0038 
0039     /// @name Reading multiple analysis objects,
0040     /// @{
0041 
0042     /// @brief Read in a collection of objects @a objs from output stream @a stream.
0043     ///
0044     /// This version fills (actually, appends to) a variable supplied container
0045     /// Note: SFINAE is used to check for a void push_back(const AnalysisObject*) method
0046     ///
0047     /// @todo Extend SFINAE Pushable cf. Writer to allow adding to containers of smart ptr type
0048     template<typename CONT>
0049     typename std::enable_if_t<YODA::Pushable<CONT,AnalysisObject*>::value>
0050     read(std::istream& stream, CONT& aos, const std::string& match = "", const std::string& unmatch = "") {
0051       // if CONT==std::vector<AnalysisObject*>, the compiler should select
0052       // the virtual method below, since it prefers non-templated methods in the lookup
0053       // otherwise we would enter a endless recursion. Check in case of problems.
0054       std::vector<AnalysisObject*> v_aos;
0055       read(stream, v_aos, match, unmatch);
0056       for (const AnalysisObject* ao : v_aos) aos.push_back(ao);
0057     }
0058 
0059     /// @brief Read in a collection of objects @a objs from output stream @a stream.
0060     ///
0061     /// This version fills (actually, appends to) a supplied vector, avoiding copying,
0062     /// and is hence CPU efficient.
0063     ///
0064     virtual void read(std::istream& stream, std::vector<AnalysisObject*>& aos,
0065                       const std::string& match = "", const std::string& unmatch = "") = 0;
0066 
0067     /// @brief Read in a collection of objects from output stream @a stream.
0068     ///
0069     /// This version returns a vector by value, involving copying, and is hence less
0070     /// CPU efficient than the alternative version where a vector is filled by reference.
0071     std::vector<AnalysisObject*> read(std::istream& stream, const std::string& match = "",
0072                                                             const std::string& unmatch = "") {
0073       std::vector<AnalysisObject*> rtn;
0074       read(stream, rtn, match, unmatch);
0075       return rtn;
0076     }
0077 
0078 
0079     /// @brief Read in a collection of objects @a objs from file @a filename.
0080     ///
0081     ///
0082     /// This version fills (actually, appends to) a variable supplied container
0083     /// Note: SFINAE is used to check for a void push_back(const AnalysisObject*) method
0084     ///
0085     /// @todo Extend SFINAE Pushable cf. Writer to allow adding to containers of smart ptr type
0086     template<typename CONT>
0087     typename std::enable_if_t<YODA::Pushable<CONT,AnalysisObject*>::value>
0088     read(const std::string& filename, CONT& aos, const std::string& match = "", const std::string& unmatch = "") {
0089       // if CONT==std::vector<AnalysisObject*>, the compiler should select
0090       // the virtual method below, since it prefers non-templated methods in the lookup
0091       // otherwise we would enter a endless recursion. Check in case of problems.
0092       std::vector<AnalysisObject*> v_aos;
0093       read(filename, v_aos, match, unmatch);
0094       for (const AnalysisObject* ao : v_aos) aos.push_back(ao);
0095     }
0096 
0097     /// @brief Read in a collection of objects @a objs from file @a filename.
0098     ///
0099     /// This version fills (actually, appends to) a supplied vector, avoiding copying,
0100     /// and is hence CPU efficient.
0101     ///
0102     void read(const std::string& filename, std::vector<AnalysisObject*>& aos, const std::string& match = "",
0103                                                                               const std::string& unmatch = "") {
0104       if (filename != "-") {
0105         try {
0106           std::ifstream instream;
0107           instream.open(filename.c_str());
0108           if (instream.fail())
0109             throw ReadError("Reading from filename " + filename + " failed");
0110           read(instream, aos, match, unmatch);
0111           instream.close();
0112         } catch (std::ifstream::failure& e) {
0113           throw ReadError("Reading from filename " + filename + " failed: " + e.what());
0114         }
0115       } else {
0116         try {
0117           read(std::cin, aos, match, unmatch);
0118         } catch (std::runtime_error& e) {
0119           throw ReadError("Reading from stdin failed: " + std::string(e.what()));
0120         }
0121       }
0122     }
0123 
0124     /// @brief Read in a collection of objects from output stream @a stream.
0125     ///
0126     /// This version returns a vector by value, involving copying, and is hence less
0127     /// CPU efficient than the alternative version where a vector is filled by reference.
0128     std::vector<AnalysisObject*> read(const std::string& filename, const std::string& match = "",
0129                                                                    const std::string& unmatch = "") {
0130       std::vector<AnalysisObject*> rtn;
0131       read(filename, rtn, match, unmatch);
0132       return rtn;
0133     }
0134 
0135     /// @}
0136 
0137     /// @name Utilities
0138     /// @{
0139 
0140     /// @brief AO type registration
0141     template<typename T>
0142     void registerType() {
0143       const string key = Utils::toUpper(T().type());
0144       const TypeRegisterItr& res = _register.find(key);
0145       if (res == _register.end())  _register[key] = std::make_unique<AOReader<T>>();
0146     }
0147 
0148     /// @brief Check if a string matches any of the given @a patterns,
0149     /// and that it doesn't match any @a unpatterns (for path filtering)
0150     bool patternCheck(const std::string& path, const std::vector<std::regex>& patterns,
0151                                                const std::vector<std::regex>& unpatterns) {
0152       bool skip = false;
0153       if (patterns.size()) {
0154         skip = true;
0155         for (const std::regex& re : patterns) {
0156           if (std::regex_search(path, re)) { skip = false; break; }
0157         }
0158       }
0159       if (!skip && unpatterns.size()) {
0160         for (const std::regex& re : unpatterns) {
0161           if (std::regex_search(path, re)) { skip = true; break; }
0162         }
0163       }
0164       return !skip;
0165     }
0166 
0167     /// @}
0168 
0169     /// Map of registered AO Readers
0170     std::unordered_map<string, std::unique_ptr<AOReaderBase>> _register;
0171 
0172   };
0173 
0174 
0175   /// Factory function to make a reader object by format name or a filename
0176   Reader& mkReader(const std::string& format_name);
0177 
0178 
0179 }
0180 
0181 #endif