lemon/lgf_reader.h
changeset 162 33247f6fff16
parent 156 e561aa7675de
child 163 c82fd9568d75
     1.1 --- a/lemon/lgf_reader.h	Mon May 26 13:50:47 2008 +0100
     1.2 +++ b/lemon/lgf_reader.h	Tue May 27 16:01:20 2008 +0200
     1.3 @@ -268,6 +268,72 @@
     1.4        str = os.str();
     1.5        return is;
     1.6      }
     1.7 +
     1.8 +    class Section {
     1.9 +    public:
    1.10 +      virtual ~Section() {}
    1.11 +      virtual void process(std::istream& is, int& line_num) = 0;
    1.12 +    };
    1.13 +
    1.14 +    template <typename Functor>
    1.15 +    class LineSection : public Section {
    1.16 +    private:
    1.17 +
    1.18 +      Functor _functor;
    1.19 +
    1.20 +    public:
    1.21 +      
    1.22 +      LineSection(const Functor& functor) : _functor(functor) {}
    1.23 +      virtual ~LineSection() {}
    1.24 +
    1.25 +      virtual void process(std::istream& is, int& line_num) {
    1.26 +	char c;
    1.27 +	std::string line;
    1.28 +	while (is.get(c) && c != '@') {
    1.29 +	  if (c == '\n') {
    1.30 +	    ++line_num;
    1.31 +	  } else if (c == '#') {
    1.32 +	    getline(is, line);
    1.33 +	    ++line_num;
    1.34 +	  } else if (!isWhiteSpace(c)) {
    1.35 +	    is.putback(c);
    1.36 +	    getline(is, line);
    1.37 +	    _functor(line);
    1.38 +	    ++line_num;
    1.39 +	  }
    1.40 +	}
    1.41 +	if (is) is.putback(c);
    1.42 +	else if (is.eof()) is.clear();
    1.43 +      }
    1.44 +    };
    1.45 +
    1.46 +    template <typename Functor>
    1.47 +    class StreamSection : public Section {
    1.48 +    private:
    1.49 +
    1.50 +      Functor _functor;
    1.51 +
    1.52 +    public:
    1.53 +      
    1.54 +      StreamSection(const Functor& functor) : _functor(functor) {}
    1.55 +      virtual ~StreamSection() {} 
    1.56 +
    1.57 +      virtual void process(std::istream& is, int& line_num) {
    1.58 +	_functor(is, line_num);
    1.59 +	char c;
    1.60 +	std::string line;
    1.61 +	while (is.get(c) && c != '@') {
    1.62 +	  if (c == '\n') {
    1.63 +	    ++line_num;
    1.64 +	  } else if (!isWhiteSpace(c)) {
    1.65 +	    getline(is, line);
    1.66 +	    ++line_num;
    1.67 +	  }
    1.68 +	}
    1.69 +	if (is) is.putback(c);
    1.70 +	else if (is.eof()) is.clear();	
    1.71 +      }
    1.72 +    };
    1.73      
    1.74    }
    1.75  
    1.76 @@ -282,13 +348,14 @@
    1.77    /// reader, and eventually the reading is executed with the \c run()
    1.78    /// member function. A map reading rule can be added to the reader
    1.79    /// with the \c nodeMap() or \c arcMap() members. An optional
    1.80 -  /// converter parameter can also be added as a standard functor converting from
    1.81 -  /// std::string to the value type of the map. If it is set, it will
    1.82 -  /// determine how the tokens in the file should be is converted to the map's
    1.83 -  /// value type. If the functor is not set, then a default conversion
    1.84 -  /// will be used. One map can be read into multiple map objects at the
    1.85 -  /// same time. The \c attribute(), \c node() and \c arc() functions
    1.86 -  /// are used to add attribute reading rules.
    1.87 +  /// converter parameter can also be added as a standard functor
    1.88 +  /// converting from std::string to the value type of the map. If it
    1.89 +  /// is set, it will determine how the tokens in the file should be
    1.90 +  /// is converted to the map's value type. If the functor is not set,
    1.91 +  /// then a default conversion will be used. One map can be read into
    1.92 +  /// multiple map objects at the same time. The \c attribute(), \c
    1.93 +  /// node() and \c arc() functions are used to add attribute reading
    1.94 +  /// rules.
    1.95    ///
    1.96    ///\code
    1.97    ///     DigraphReader<Digraph>(std::cin, digraph).
    1.98 @@ -302,9 +369,10 @@
    1.99    ///
   1.100    /// By default the reader uses the first section in the file of the
   1.101    /// proper type. If a section has an optional name, then it can be
   1.102 -  /// selected for reading by giving an optional name parameter to
   1.103 -  /// the \c nodes(), \c arcs() or \c attributes()
   1.104 -  /// functions.
   1.105 +  /// selected for reading by giving an optional name parameter to the
   1.106 +  /// \c nodes(), \c arcs() or \c attributes() functions. The readers
   1.107 +  /// also can load extra sections with the \c sectionLines() and
   1.108 +  /// sectionStream() functions.
   1.109    ///
   1.110    /// The \c useNodes() and \c useArcs() functions are used to tell the reader
   1.111    /// that the nodes or arcs should not be constructed (added to the
   1.112 @@ -356,6 +424,9 @@
   1.113        Attributes;
   1.114      Attributes _attributes;
   1.115  
   1.116 +    typedef std::map<std::string, _reader_bits::Section*> Sections;
   1.117 +    Sections _sections;
   1.118 +
   1.119      bool _use_nodes;
   1.120      bool _use_arcs;
   1.121  
   1.122 @@ -409,6 +480,8 @@
   1.123        _nodes_caption = other._nodes_caption;
   1.124        _arcs_caption = other._arcs_caption;
   1.125        _attributes_caption = other._attributes_caption;
   1.126 +
   1.127 +      _sections.swap(other._sections);
   1.128      }
   1.129  
   1.130      /// \brief Destructor
   1.131 @@ -428,6 +501,11 @@
   1.132  	delete it->second;
   1.133        }
   1.134  
   1.135 +      for (typename Sections::iterator it = _sections.begin(); 
   1.136 +	   it != _sections.end(); ++it) {
   1.137 +	delete it->second;
   1.138 +      }
   1.139 +
   1.140        if (local_is) {
   1.141  	delete _is;
   1.142        }
   1.143 @@ -574,6 +652,83 @@
   1.144  
   1.145      /// @}
   1.146  
   1.147 +    /// \name Section readers
   1.148 +    /// @{
   1.149 +
   1.150 +    /// \brief Add a section processor with line oriented reading
   1.151 +    ///
   1.152 +    /// In the \e LGF file extra sections can be placed, which contain
   1.153 +    /// any data in arbitrary format. These sections can be read with
   1.154 +    /// this function line by line. The first parameter is the type
   1.155 +    /// descriptor of the section, the second is a functor, which
   1.156 +    /// takes just one \c std::string parameter. At the reading
   1.157 +    /// process, each line of the section will be given to the functor
   1.158 +    /// object. However, the empty lines and the comment lines are
   1.159 +    /// filtered out, and the leading whitespaces are stipped from
   1.160 +    /// each processed string.
   1.161 +    ///
   1.162 +    /// For example let's see a section, which contain several
   1.163 +    /// integers, which should be inserted into a vector.
   1.164 +    ///\code
   1.165 +    ///  @numbers
   1.166 +    ///  12 45 23
   1.167 +    ///  4
   1.168 +    ///  23 6
   1.169 +    ///\endcode
   1.170 +    ///
   1.171 +    /// The functor is implemented as an struct:
   1.172 +    ///\code
   1.173 +    ///  struct NumberSection {
   1.174 +    ///    std::vector<int>& _data;
   1.175 +    ///    NumberSection(std::vector<int>& data) : _data(data) {}
   1.176 +    ///    void operator()(const std::string& line) {
   1.177 +    ///      std::istringstream ls(line);
   1.178 +    ///      int value;
   1.179 +    ///      while (ls >> value) _data.push_back(value);
   1.180 +    ///    }
   1.181 +    ///  };
   1.182 +    ///
   1.183 +    ///  // ...
   1.184 +    ///
   1.185 +    ///  reader.sectionLines("numbers", NumberSection(vec));  
   1.186 +    ///\endcode
   1.187 +    template <typename Functor>
   1.188 +    DigraphReader& sectionLines(const std::string& type, Functor functor) {
   1.189 +      LEMON_ASSERT(!type.empty(), "Type is not empty.");
   1.190 +      LEMON_ASSERT(_sections.find(type) == _sections.end(), 
   1.191 +		   "Multiple reading of section.");
   1.192 +      LEMON_ASSERT(type != "nodes" && type != "arcs" && type != "edges" &&
   1.193 +		   type != "attributes", "Multiple reading of section.");
   1.194 +      _sections.insert(std::make_pair(type, 
   1.195 +        new _reader_bits::LineSection<Functor>(functor)));
   1.196 +      return *this;
   1.197 +    }
   1.198 +
   1.199 +
   1.200 +    /// \brief Add a section processor with stream oriented reading
   1.201 +    ///
   1.202 +    /// In the \e LGF file extra sections can be placed, which contain
   1.203 +    /// any data in arbitrary format. These sections can be read
   1.204 +    /// directly with this function. The first parameter is the type
   1.205 +    /// of the section, the second is a functor, which takes an \c
   1.206 +    /// std::istream& and an int& parameter, the latter regard to the
   1.207 +    /// line number of stream. The functor can read the input while
   1.208 +    /// the section go on, and the line number should be modified
   1.209 +    /// accordingly.
   1.210 +    template <typename Functor>
   1.211 +    DigraphReader& sectionStream(const std::string& type, Functor functor) {
   1.212 +      LEMON_ASSERT(!type.empty(), "Type is not empty.");
   1.213 +      LEMON_ASSERT(_sections.find(type) == _sections.end(), 
   1.214 +		   "Multiple reading of section.");
   1.215 +      LEMON_ASSERT(type != "nodes" && type != "arcs" && type != "edges" &&
   1.216 +		   type != "attributes", "Multiple reading of section.");
   1.217 +      _sections.insert(std::make_pair(type, 
   1.218 +	 new _reader_bits::StreamSection<Functor>(functor)));
   1.219 +      return *this;
   1.220 +    }    
   1.221 +    
   1.222 +    /// @}
   1.223 +
   1.224      /// \name Using previously constructed node or arc set
   1.225      /// @{
   1.226  
   1.227 @@ -929,6 +1084,7 @@
   1.228        bool nodes_done = false;
   1.229        bool arcs_done = false;
   1.230        bool attributes_done = false;
   1.231 +      std::set<std::string> extra_sections;
   1.232  
   1.233        line_num = 0;      
   1.234        readLine();
   1.235 @@ -962,8 +1118,20 @@
   1.236  	      attributes_done = true;
   1.237  	    }
   1.238  	  } else {
   1.239 -	    readLine();
   1.240 -	    skipSection();
   1.241 +	    if (extra_sections.find(section) != extra_sections.end()) {
   1.242 +	      std::ostringstream msg;
   1.243 +	      msg << "Multiple occurence of section " << section;
   1.244 +	      throw DataFormatError(msg.str().c_str());
   1.245 +	    }
   1.246 +	    Sections::iterator it = _sections.find(section);
   1.247 +	    if (it != _sections.end()) {
   1.248 +	      extra_sections.insert(section);
   1.249 +	      it->second->process(*_is, line_num);
   1.250 +	      readLine();
   1.251 +	    } else {
   1.252 +	      readLine();
   1.253 +	      skipSection();
   1.254 +	    }
   1.255  	  }
   1.256  	} catch (DataFormatError& error) {
   1.257  	  error.line(line_num);