#ifndef __JSUPPORT__JMULTIPLEFILESCANNER__ #define __JSUPPORT__JMULTIPLEFILESCANNER__ #include #include #include #include #include "TChain.h" #include "TChainElement.h" #include "JLang/JObjectIterator.hh" #include "JLang/JTypeList.hh" #include "JLang/JNullType.hh" #include "JLang/JMultiEquals.hh" #include "JLang/JException.hh" #include "JSystem/JGlob.hh" #include "JSupport/JLimit.hh" #include "JSupport/JFileScanner.hh" /** * \file * Scanning of objects from multiple files according a format that follows from the extension of each file name. * \author mdejong */ namespace JSUPPORT {} namespace JPP { using namespace JSUPPORT; } namespace JSUPPORT { using JLANG::JRewindableObjectIterator; using JLANG::JPointer; using JLANG::JTypeList; using JLANG::JTYPELIST; using JLANG::JNullType; using JLANG::JMultiEquals; using JLANG::skip_type; using JLANG::JException; /** * Auxiliary base class for list of file names. */ struct JMultipleFileScanner_t : public std::vector { /** * Default constructor. */ JMultipleFileScanner_t() {} /** * Constructor. * * \param file_name file name */ JMultipleFileScanner_t(const std::string& file_name) : std::vector(1, file_name) {} /** * Constructor. * * \param file_list file list */ JMultipleFileScanner_t(const std::vector& file_list) : std::vector(file_list) {} /** * Constructor. * * \param chain ROOT chain */ JMultipleFileScanner_t(const TChain& chain) { const TObjArray* array = chain.GetListOfFiles(); for (Int_t i = 0; i != array->GetEntries(); ++i) { const TChainElement* p = (const TChainElement*) array->At(i); this->push_back(p->GetTitle()); } } /** * Get file list. * * \return list of file names */ const JMultipleFileScanner_t& getFilelist() const { return static_cast(*this); } /** * Get file list. * * \return list of file names */ JMultipleFileScanner_t& getFilelist() { return static_cast(*this); } /** * Set file list. * * \param file_list list of file names */ void setFilelist(const JMultipleFileScanner_t& file_list) { static_cast(*this) = file_list; } /** * Add file list. * * \param file_list list of file names */ void addFilelist(const JMultipleFileScanner_t& file_list) { for (const_iterator i = file_list.begin(); i != file_list.end(); ++i) { this->push_back(*i); } } /** * Read file list from input. * * \param in input stream * \param object file list * \return input stream */ friend inline std::istream& operator>>(std::istream& in, JMultipleFileScanner_t& object) { using namespace std; using namespace JPP; for (string buffer; in >> buffer; ) { if (getFilenameExtension(buffer) == FILE_LIST_FORMAT) { ifstream ls(buffer.c_str()); ls >> object; ls.close(); } else { try { object.addFilelist(getFilenames(buffer)); } catch(const exception&) { object.addFilelist(buffer); } } } return in; } /** * Write file list to output. * * \param out output stream * \param object file list * \return output stream */ friend inline std::ostream& operator<<(std::ostream& out, const JMultipleFileScanner_t& object) { for (const_iterator i = object.begin(); i != object.end(); ++i) { out << *i << std::endl; } return out; } }; /** * General purpose class for object reading from a list of file names. */ template class JMultipleFileScanner; /** * Template specialisation of JMultipleFileScanner for undefined type.\n * This specialisation is used as a virtual base class for all implementations of JMultipleFileScanner for defined type(s).\n * The method JMultipleFileScanner::configure should be used to set the internal parameters. * * This class is a simple container for a list of file names and has an additional counter limit by extending from JSUPPORT::JLimit.\n * This counter limit will be used to limit the number of calls to the method next of the derived class.\n * Note that the counter limit can only be set via the member or friend methods of class JSUPPORT::JLimit. */ template<> class JMultipleFileScanner : public JMultipleFileScanner_t, public JLimit, public JMultiEquals, JTYPELIST::typelist> { public: typedef JMultipleFileScanner_t input_type; /** * Default constructor. */ JMultipleFileScanner() {} /** * Virtual destructor. */ virtual ~JMultipleFileScanner() {} /** * Configure. * * \param input list of file names * \param limit limit */ void configure(const input_type& input, const JLimit& limit) { this->setFilelist(input); this->setLimit (limit); } /** * Configure. * * \param input list of file names */ void configure(const input_type& input) { this->configure(input, JLimit()); } /** * Read multiple file scanner from input. * * Note that only file names are read. * * \param in input stream * \param object multiple file scanner * \return input stream */ friend inline std::istream& operator>>(std::istream& in, JMultipleFileScanner& object) { return in >> object.getFilelist(); } /** * Write multiple file scanner to output. * * Note that only file names are written. * * \param out output stream * \param object multiple file scanner * \return output stream */ friend inline std::ostream& operator<<(std::ostream& out, const JMultipleFileScanner& object) { return out << object.getFilelist(); } }; /** * Implementation of object reading for single data type from a list of file names. * * This class extends the JMultipleFileScanner class and * implements the JLANG::JRewindableObjectIterator interface.\n * When the method hasNext() is called, * the next file in the list is opened when the previous file is exhausted. */ template class JMultipleFileScanner : public virtual JMultipleFileScanner<>, public JRewindableObjectIterator { public: typedef JMultipleFileScanner<>::input_type input_type; typedef typename JRewindableObjectIterator::pointer_type pointer_type; /** * Default constructor. */ JMultipleFileScanner() : index (0), counter(0) {} /** * Copy constructor. * * Note that the counter limit is not copied and the index and counter are set to zero. * * \param input input */ template JMultipleFileScanner(const JMultipleFileScanner& input) : index (0), counter(0) { this->configure(input.getFilelist(), JLimit()); } /** * Constructor. * * \param file_list list of file names */ JMultipleFileScanner(const input_type& file_list) : index (0), counter(0) { configure(file_list, JLimit()); } /** * Constructor. * * \param file_list list of file names * \param limit limit */ JMultipleFileScanner(const input_type& file_list, const JLimit& limit) : index (0), counter(0) { configure(file_list, limit); } /** * Get current file name. * * Note that this method should only be called when method hasNext() returns true. * * \return file name */ const std::string& getFilename() const { return this->at(index); } /** * Get counter. * * \return counter */ counter_type getCounter() const { return counter; } /** * Rewind. */ virtual void rewind() override { if (scanner.is_open()) { scanner.close(); } index = 0; counter = 0; scanner.reset(); } /** * Check availability of next element. * * \return true if the iteration has more elements; else false */ virtual bool hasNext() override { if (is_valid()) { if (counter < getUpperLimit() && index != this->size()) { // first time around if (!scanner.is_open()) { scanner.open(getFilename().c_str()); } if (counter < getLowerLimit()) { counter += scanner.skip(getLowerLimit() - counter); } if (!scanner.hasNext()) { scanner.close(); ++index; return hasNext(); } return true; } else { // last time around if (scanner.is_open()) { scanner.close(); } scanner.reset(); } } return false; } /** * Get next element. * * \return pointer to element */ virtual const pointer_type& next() override { ++counter; return scanner.next(); } /** * Skip items. * * \param ns number of items to skip * \return number of items skipped */ virtual skip_type skip(const skip_type ns) override { skip_type i = 0; while (this->hasNext() && i != ns) { i += scanner.skip(ns - i); } counter += i; return i; } protected: JFileScanner scanner; unsigned int index; counter_type counter; }; /** * Implementation of object reading for multiple data types from a list of file names. * * This class recursively implements the JLANG::JRewindableObjectIterator interface * for all data types by deriving from: * - JMultipleFileScanner; and * - JMultipleFileScanner. * * The method rewind(), rewinds each object iterator. */ template class JMultipleFileScanner< JTypeList > : public virtual JMultipleFileScanner<>, public JRewindableObjectIterator< JTypeList >, public JMultipleFileScanner, public JMultipleFileScanner { public: typedef JMultipleFileScanner<>::input_type input_type; using JMultipleFileScanner::hasNext; using JMultipleFileScanner::next; /** * Default constructor. */ JMultipleFileScanner() : JMultipleFileScanner<>() {} /** * Copy constructor. * * Note that the counter limit is not copied and the index and counter are set to zero. * * \param input input */ template JMultipleFileScanner(const JMultipleFileScanner& input) { this->configure(input.getFilelist(), JLimit()); } /** * Constructor. * * \param file_list list of file names */ JMultipleFileScanner(const input_type& file_list) { this->configure(file_list, JLimit()); } /** * Constructor. * * \param file_list list of file names * \param limit limit */ JMultipleFileScanner(const input_type& file_list, const JLimit& limit) { this->configure(file_list, limit); } /** * Rewind.\n * This method rewinds the JMultipleFileScanner for each data type. */ virtual void rewind() override { JMultipleFileScanner::rewind(); JMultipleFileScanner::rewind(); } /** * Skip items. * * \param ns number of items to skip * \return number of items skipped */ virtual skip_type skip(const skip_type ns) override { if (JMultipleFileScanner::skip(ns) == ns && JMultipleFileScanner::skip(ns) == ns) return ns; else throw JException("JMultipleFileScanner::skip(): inconsistent number of items skipped."); } }; /** * Terminator class of recursive JMultipleFileScanner class. */ template class JMultipleFileScanner< JTypeList > : public JMultipleFileScanner { public: typedef JMultipleFileScanner<>::input_type input_type; /** * Default constructor. */ JMultipleFileScanner() : JMultipleFileScanner() {} /** * Copy constructor. * * Note that the counter limit is not copied and the index and counter are set to zero. * * \param input input */ template JMultipleFileScanner(const JMultipleFileScanner& input) { this->configure(input.getFilelist(), JLimit()); } /** * Constructor. * * \param file_list list of file names */ JMultipleFileScanner(const input_type& file_list) { this->configure(file_list, JLimit()); } /** * Constructor. * * \param file_list list of file names * \param limit limit */ JMultipleFileScanner(const input_type& file_list, const JLimit& limit) { this->configure(file_list, limit); } }; } #endif