#ifndef __JSUPPORT__JSINGLEFILESCANNER__ #define __JSUPPORT__JSINGLEFILESCANNER__ #include #include #include "JLang/JObjectIterator.hh" #include "JLang/JTypeList.hh" #include "JLang/JNullType.hh" #include "JLang/JMultiEquals.hh" #include "JLang/JException.hh" #include "JSupport/JLimit.hh" #include "JSupport/JFileScanner.hh" /** * \file * Scanning of objects from a single file 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::JTypeList; using JLANG::JTYPELIST; using JLANG::JNullType; using JLANG::JMultiEquals; using JLANG::skip_type; using JLANG::JException; /** * Auxiliary base class for file name. */ struct JSingleFileScanner_t : public std::string { /** * Default constructor. */ JSingleFileScanner_t() {} /** * Constructor. * * \param file_name file name */ JSingleFileScanner_t(const std::string& file_name) : std::string(file_name) {} /** * Get file name. * * \return file name */ const JSingleFileScanner_t& getFilename() const { return static_cast(*this); } }; /** * Object reading from a list of files. */ template class JSingleFileScanner; /** * Template specialisation of JSingleFileScanner for undefined type.\n * This specialisation is used as a virtual base class for all implementations of JSingleFileScanner for defined type(s). * * This class is a simple container for a single file name 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 JSUPPORT::JLimit. */ template<> class JSingleFileScanner : public JSingleFileScanner_t, public JLimit, public JMultiEquals, JTYPELIST::typelist> { public: typedef JSingleFileScanner_t input_type; /** * Default constructor. */ JSingleFileScanner() {} /** * Virtual destructor. */ virtual ~JSingleFileScanner() {} /** * Configure. * * \param input file name * \param limit limit */ void configure(const input_type& input, const JLimit& limit) { static_cast(*this) = input; this->setLimit(limit); } /** * Read single file scanner from input. * * \param in input stream * \param file_name single file scanner * \return input stream */ friend inline std::istream& operator>>(std::istream& in, JSingleFileScanner& file_name) { return in >> static_cast(file_name); } /** * Write single file scanner to output. * * \param out output stream * \param file_name single file scanner * \return output stream */ friend inline std::ostream& operator<<(std::ostream& out, const JSingleFileScanner& file_name) { return out << static_cast(file_name); } }; /** * Object reading from a single file name. * * This class implements the JLANG::JRewindableObjectIterator interface. */ template class JSingleFileScanner : public virtual JSingleFileScanner<>, public JRewindableObjectIterator { public: typedef JSingleFileScanner<>::input_type input_type; typedef typename JRewindableObjectIterator::pointer_type pointer_type; /** * Default constructor. */ JSingleFileScanner() : counter(0) {} /** * Copy constructor. * * Note that the counter limit is not copied and the counter is set to zero. * * \param input input */ template JSingleFileScanner(const JSingleFileScanner& input) : counter(0) { this->configure(input.getFilename(), JLimit()); } /** * Constructor. * * \param file_name file name */ JSingleFileScanner(const input_type& file_name) : counter(0) { this->configure(file_name, JLimit()); } /** * Constructor. * * \param file_name file name * \param limit limit */ JSingleFileScanner(const input_type& file_name, const JLimit& limit) : counter(0) { this->configure(file_name, limit); } /** * Get counter. * * \return counter */ counter_type getCounter() const { return counter; } /** * Rewind. */ virtual void rewind() override { if (scanner.is_open()) { scanner.close(); } 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()) { // first time around if (!scanner.is_open()) { scanner.open(this->getFilename().c_str()); } if (counter < getLowerLimit()) { counter += scanner.skip(getLowerLimit() - counter); } if (!scanner.hasNext()) { scanner.close(); return false; } 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 { const skip_type previous = counter; counter += scanner.skip(ns); return counter - previous; } protected: JFileScanner scanner; counter_type counter; }; /** * Template specialisation of JSingleFileScanner for single data types. * * This class implements the JLANG::JRewindableObjectIterator interface for * each data type. * The method rewind(), rewinds each object iterator. */ template class JSingleFileScanner< JTypeList > : public virtual JSingleFileScanner<>, public JSingleFileScanner, public JSingleFileScanner, public JRewindableObjectIterator< JTypeList > { public: typedef JSingleFileScanner<>::input_type input_type; using JSingleFileScanner::hasNext; using JSingleFileScanner::next; /** * Default constructor. */ JSingleFileScanner() : JSingleFileScanner<>() {} /** * Copy constructor. * * Note that the counter limit is not copied and the counter is set to zero. * * \param input input */ template JSingleFileScanner(const JSingleFileScanner& input) { this->configure(input.getFilename(), JLimit()); } /** * Constructor. * * \param file_name file name */ JSingleFileScanner(const input_type& file_name) { this->configure(file_name, JLimit()); } /** * Constructor. * * \param file_name file name * \param limit limit */ JSingleFileScanner(const input_type& file_name, const JLimit& limit) { this->configure(file_name, limit); } /** * Rewind.\n * This method rewinds the JSingleFileScanner for each data type. */ virtual void rewind() override { JSingleFileScanner::rewind(); JSingleFileScanner::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 (JSingleFileScanner::skip(ns) == ns && JSingleFileScanner::skip(ns) == ns) return ns; else throw JException("JSingleFileScanner::skip(): inconsistent number of items skipped."); } }; /** * Terminator class of recursive JSingleFileScanner class. */ template class JSingleFileScanner< JTypeList > : public JSingleFileScanner { public: typedef JSingleFileScanner<>::input_type input_type; /** * Default constructor. */ JSingleFileScanner() : JSingleFileScanner() {} /** * Copy constructor. * * Note that the counter limit is not copied and the counter is set to zero. * * \param input input */ template JSingleFileScanner(const JSingleFileScanner& input) { this->configure(input.getFilename(), JLimit()); } /** * Constructor. * * \param file_name file name */ JSingleFileScanner(const input_type& file_name) : JSingleFileScanner() { this->configure(file_name, JLimit()); } /** * Constructor. * * \param file_name file name * \param limit limit */ JSingleFileScanner(const input_type& file_name, const JLimit& limit) : JSingleFileScanner() { this->configure(file_name, limit); } }; } #endif