Back to home page

EIC code displayed by LXR

 
 

    


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

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_Writer_h
0007 #define YODA_Writer_h
0008 
0009 #include "YODA/AnalysisObject.h"
0010 #include "YODA/Utils/Traits.h"
0011 #include <type_traits>
0012 #include <fstream>
0013 #include <iostream>
0014 
0015 namespace YODA {
0016 
0017 
0018   /// Pure virtual base class for various output writers.
0019   class Writer {
0020   public:
0021 
0022     /// Virtual destructor
0023     virtual ~Writer() {}
0024 
0025 
0026     /// @name Writing a single analysis object.
0027     /// @{
0028 
0029     /// Write out object @a ao to file @a filename.
0030     void write(const std::string& filename, const AnalysisObject& ao);
0031 
0032     /// Write out object @a ao to output stream @a stream.
0033     void write(std::ostream& stream, const AnalysisObject& ao) {
0034       // std::vector<const AnalysisObject*> vec{&ao};
0035       std::vector<const AnalysisObject*> vec{&ao};
0036       write(stream, vec);
0037     }
0038 
0039     /// Write out pointer-like object @a ao to output stream @a stream.
0040     template <typename T>
0041     typename std::enable_if_t<DerefableToAO<T>::value> //< -> void if valid
0042     write(std::ostream& stream, const T& ao) {
0043       write(stream, *ao);
0044     }
0045 
0046     /// Write out pointer-like object @a ao to file @a filename.
0047     template <typename T>
0048     typename std::enable_if_t<DerefableToAO<T>::value> //< -> void if valid
0049     write(const std::string& filename, const T& ao) {
0050       write(filename, *ao);
0051     }
0052 
0053     /// @}
0054 
0055 
0056     /// @name Writing multiple analysis objects by collection.
0057     /// @{
0058 
0059     /// Write out a vector of AO pointers (untemplated=exact type-match) to the given stream
0060     ///
0061     /// @note This is the canonical function for implementing AO writing: all
0062     /// others call this. Hence the specific AOs type.
0063     ///
0064     /// @note Among other reasons, this is non-inline to hide zstr from the public API
0065     void write(std::ostream& stream, const std::vector<const AnalysisObject*>& aos);
0066 
0067 
0068     /// Write out a collection of objects @a objs to output stream @a stream.
0069     ///
0070     /// @note The enable_if call checks whether RANGE is const_iterable, if yes the return
0071     ///       type is void. If not, this template will not be a candidate in the lookup
0072     template <typename RANGE>
0073     typename std::enable_if_t<CIterable<RANGE>::value>
0074     write(std::ostream& stream, const RANGE& aos) {
0075       write(stream, std::begin(aos), std::end(aos));
0076     }
0077 
0078     /// Write out a collection of objects @a objs to file @a filename.
0079     template <typename RANGE>
0080     typename std::enable_if_t<CIterable<RANGE>::value>
0081     write(const std::string& filename, const RANGE& aos) {
0082       write(filename, std::begin(aos), std::end(aos));
0083     }
0084 
0085     /// @}
0086 
0087 
0088     /// @name Writing multiple analysis objects by iterator range.
0089     /// @{
0090 
0091     /// Write out the objects specified by start iterator @a begin and end
0092     /// iterator @a end to output stream @a stream.
0093     ///
0094     /// @todo Add SFINAE trait checking for AOITER = DerefableToAO
0095     template <typename AOITER>
0096     void write(std::ostream& stream, const AOITER& begin, const AOITER& end) {
0097       std::vector<const AnalysisObject*> vec;
0098       // vec.reserve(std::distance(begin, end));
0099       for (AOITER ipao = begin; ipao != end; ++ipao)  vec.push_back(&(**ipao));
0100       write(stream, vec);
0101     }
0102 
0103 
0104     /// Write out the objects specified by start iterator @a begin and end
0105     /// iterator @a end to file @a filename.
0106     ///
0107     /// @todo Add SFINAE trait checking for AOITER = DerefableToAO
0108     template <typename AOITER>
0109     void write(const std::string& filename, const AOITER& begin, const AOITER& end) {
0110       std::vector<const AnalysisObject*> vec;
0111       // vec.reserve(std::distance(begin, end));
0112       for (AOITER ipao = begin; ipao != end; ++ipao)  vec.push_back(&(**ipao));
0113 
0114       if (filename != "-") {
0115         try {
0116           const size_t lastdot = filename.find_last_of(".");
0117           std::string fmt = Utils::toLower(lastdot == std::string::npos ? filename : filename.substr(lastdot+1));
0118           const bool compress = (fmt == "gz");
0119           useCompression(compress);
0120           //
0121           std::ofstream stream;
0122           stream.exceptions(std::ofstream::failbit | std::ofstream::badbit);
0123           stream.open(filename.c_str());
0124           if (stream.fail())
0125             throw WriteError("Writing to filename " + filename + " failed");
0126           write(stream, vec);
0127         } catch (std::ofstream::failure& e) {
0128           throw WriteError("Writing to filename " + filename + " failed: " + e.what());
0129         }
0130       } else {
0131         try {
0132           write(std::cout, vec);
0133         } catch (std::runtime_error& e) {
0134           throw WriteError("Writing to stdout failed: " + std::string(e.what()));
0135         }
0136       }
0137 
0138     }
0139 
0140     /// @}
0141 
0142     /// Set precision of numerical quantities in this writer's output.
0143     void setPrecision(int precision) {
0144       _precision = precision;
0145     }
0146 
0147     /// Set precision of numerical quantities for current AO in this writer's output.
0148     void setAOPrecision(const bool needsDP = false) {
0149       _aoprecision = needsDP? std::numeric_limits<double>::max_digits10 : _precision;
0150     }
0151 
0152     /// Use libz compression?
0153     void useCompression(const bool compress=true) {
0154       _compress = compress;
0155     }
0156 
0157 
0158   protected:
0159 
0160     /// @name Main writer elements
0161     /// @{
0162 
0163     /// Write any opening boilerplate required by the format to @a stream
0164     virtual void writeHead(std::ostream&) {}
0165 
0166     /// @brief Write the body elements corresponding to AnalysisObject @a ao to @a stream
0167     virtual void writeBody(std::ostream& stream, const AnalysisObject* ao);
0168 
0169     /// @brief Write the body elements corresponding to AnalysisObject pointer @a ao to @a stream
0170     virtual void writeBody(std::ostream& stream, const AnalysisObject& ao);
0171 
0172     /// @brief Write the body elements corresponding to AnalysisObject @a ao to @a stream
0173     /// @note Requires that @a ao is dereferenceable to an AnalysisObject, via the DerefableToAO<T> trait,
0174     template <typename T>
0175     typename std::enable_if_t<DerefableToAO<T>::value> //< -> void if valid
0176     writeBody(std::ostream& stream, const T& ao) { writeBody(stream, *ao); }
0177 
0178     /// Write any closing boilerplate required by the format to @a stream
0179     virtual void writeFoot(std::ostream& stream) { stream << std::flush; }
0180 
0181     /// @}
0182 
0183 
0184     /// @name Specific AO type writer implementations, to be implemented in derived classes
0185     /// @{
0186 
0187     virtual void writeAO(std::ostream& stream, const AnalysisObject& ao) = 0;
0188 
0189     /// @}
0190 
0191 
0192     /// Output precision
0193     int _precision, _aoprecision;
0194 
0195     /// Compress the output?
0196     bool _compress;
0197 
0198   };
0199 
0200 
0201   /// Factory function to make a writer object by format name or a filename
0202   Writer& mkWriter(const std::string& format_name);
0203 
0204 
0205 }
0206 
0207 #endif