266 } |
266 } |
267 } |
267 } |
268 str = os.str(); |
268 str = os.str(); |
269 return is; |
269 return is; |
270 } |
270 } |
|
271 |
|
272 class Section { |
|
273 public: |
|
274 virtual ~Section() {} |
|
275 virtual void process(std::istream& is, int& line_num) = 0; |
|
276 }; |
|
277 |
|
278 template <typename Functor> |
|
279 class LineSection : public Section { |
|
280 private: |
|
281 |
|
282 Functor _functor; |
|
283 |
|
284 public: |
|
285 |
|
286 LineSection(const Functor& functor) : _functor(functor) {} |
|
287 virtual ~LineSection() {} |
|
288 |
|
289 virtual void process(std::istream& is, int& line_num) { |
|
290 char c; |
|
291 std::string line; |
|
292 while (is.get(c) && c != '@') { |
|
293 if (c == '\n') { |
|
294 ++line_num; |
|
295 } else if (c == '#') { |
|
296 getline(is, line); |
|
297 ++line_num; |
|
298 } else if (!isWhiteSpace(c)) { |
|
299 is.putback(c); |
|
300 getline(is, line); |
|
301 _functor(line); |
|
302 ++line_num; |
|
303 } |
|
304 } |
|
305 if (is) is.putback(c); |
|
306 else if (is.eof()) is.clear(); |
|
307 } |
|
308 }; |
|
309 |
|
310 template <typename Functor> |
|
311 class StreamSection : public Section { |
|
312 private: |
|
313 |
|
314 Functor _functor; |
|
315 |
|
316 public: |
|
317 |
|
318 StreamSection(const Functor& functor) : _functor(functor) {} |
|
319 virtual ~StreamSection() {} |
|
320 |
|
321 virtual void process(std::istream& is, int& line_num) { |
|
322 _functor(is, line_num); |
|
323 char c; |
|
324 std::string line; |
|
325 while (is.get(c) && c != '@') { |
|
326 if (c == '\n') { |
|
327 ++line_num; |
|
328 } else if (!isWhiteSpace(c)) { |
|
329 getline(is, line); |
|
330 ++line_num; |
|
331 } |
|
332 } |
|
333 if (is) is.putback(c); |
|
334 else if (is.eof()) is.clear(); |
|
335 } |
|
336 }; |
271 |
337 |
272 } |
338 } |
273 |
339 |
274 /// \ingroup lemon_io |
340 /// \ingroup lemon_io |
275 /// |
341 /// |
280 /// The reading method does a batch processing. The user creates a |
346 /// The reading method does a batch processing. The user creates a |
281 /// reader object, then various reading rules can be added to the |
347 /// reader object, then various reading rules can be added to the |
282 /// reader, and eventually the reading is executed with the \c run() |
348 /// reader, and eventually the reading is executed with the \c run() |
283 /// member function. A map reading rule can be added to the reader |
349 /// member function. A map reading rule can be added to the reader |
284 /// with the \c nodeMap() or \c arcMap() members. An optional |
350 /// with the \c nodeMap() or \c arcMap() members. An optional |
285 /// converter parameter can also be added as a standard functor converting from |
351 /// converter parameter can also be added as a standard functor |
286 /// std::string to the value type of the map. If it is set, it will |
352 /// converting from std::string to the value type of the map. If it |
287 /// determine how the tokens in the file should be is converted to the map's |
353 /// is set, it will determine how the tokens in the file should be |
288 /// value type. If the functor is not set, then a default conversion |
354 /// is converted to the map's value type. If the functor is not set, |
289 /// will be used. One map can be read into multiple map objects at the |
355 /// then a default conversion will be used. One map can be read into |
290 /// same time. The \c attribute(), \c node() and \c arc() functions |
356 /// multiple map objects at the same time. The \c attribute(), \c |
291 /// are used to add attribute reading rules. |
357 /// node() and \c arc() functions are used to add attribute reading |
|
358 /// rules. |
292 /// |
359 /// |
293 ///\code |
360 ///\code |
294 /// DigraphReader<Digraph>(std::cin, digraph). |
361 /// DigraphReader<Digraph>(std::cin, digraph). |
295 /// nodeMap("coordinates", coord_map). |
362 /// nodeMap("coordinates", coord_map). |
296 /// arcMap("capacity", cap_map). |
363 /// arcMap("capacity", cap_map). |
300 /// run(); |
367 /// run(); |
301 ///\endcode |
368 ///\endcode |
302 /// |
369 /// |
303 /// By default the reader uses the first section in the file of the |
370 /// By default the reader uses the first section in the file of the |
304 /// proper type. If a section has an optional name, then it can be |
371 /// proper type. If a section has an optional name, then it can be |
305 /// selected for reading by giving an optional name parameter to |
372 /// selected for reading by giving an optional name parameter to the |
306 /// the \c nodes(), \c arcs() or \c attributes() |
373 /// \c nodes(), \c arcs() or \c attributes() functions. The readers |
307 /// functions. |
374 /// also can load extra sections with the \c sectionLines() and |
|
375 /// sectionStream() functions. |
308 /// |
376 /// |
309 /// The \c useNodes() and \c useArcs() functions are used to tell the reader |
377 /// The \c useNodes() and \c useArcs() functions are used to tell the reader |
310 /// that the nodes or arcs should not be constructed (added to the |
378 /// that the nodes or arcs should not be constructed (added to the |
311 /// graph) during the reading, but instead the label map of the items |
379 /// graph) during the reading, but instead the label map of the items |
312 /// are given as a parameter of these functions. An |
380 /// are given as a parameter of these functions. An |
570 DigraphReader& attributes(const std::string& caption) { |
648 DigraphReader& attributes(const std::string& caption) { |
571 _attributes_caption = caption; |
649 _attributes_caption = caption; |
572 return *this; |
650 return *this; |
573 } |
651 } |
574 |
652 |
|
653 /// @} |
|
654 |
|
655 /// \name Section readers |
|
656 /// @{ |
|
657 |
|
658 /// \brief Add a section processor with line oriented reading |
|
659 /// |
|
660 /// In the \e LGF file extra sections can be placed, which contain |
|
661 /// any data in arbitrary format. These sections can be read with |
|
662 /// this function line by line. The first parameter is the type |
|
663 /// descriptor of the section, the second is a functor, which |
|
664 /// takes just one \c std::string parameter. At the reading |
|
665 /// process, each line of the section will be given to the functor |
|
666 /// object. However, the empty lines and the comment lines are |
|
667 /// filtered out, and the leading whitespaces are stipped from |
|
668 /// each processed string. |
|
669 /// |
|
670 /// For example let's see a section, which contain several |
|
671 /// integers, which should be inserted into a vector. |
|
672 ///\code |
|
673 /// @numbers |
|
674 /// 12 45 23 |
|
675 /// 4 |
|
676 /// 23 6 |
|
677 ///\endcode |
|
678 /// |
|
679 /// The functor is implemented as an struct: |
|
680 ///\code |
|
681 /// struct NumberSection { |
|
682 /// std::vector<int>& _data; |
|
683 /// NumberSection(std::vector<int>& data) : _data(data) {} |
|
684 /// void operator()(const std::string& line) { |
|
685 /// std::istringstream ls(line); |
|
686 /// int value; |
|
687 /// while (ls >> value) _data.push_back(value); |
|
688 /// } |
|
689 /// }; |
|
690 /// |
|
691 /// // ... |
|
692 /// |
|
693 /// reader.sectionLines("numbers", NumberSection(vec)); |
|
694 ///\endcode |
|
695 template <typename Functor> |
|
696 DigraphReader& sectionLines(const std::string& type, Functor functor) { |
|
697 LEMON_ASSERT(!type.empty(), "Type is not empty."); |
|
698 LEMON_ASSERT(_sections.find(type) == _sections.end(), |
|
699 "Multiple reading of section."); |
|
700 LEMON_ASSERT(type != "nodes" && type != "arcs" && type != "edges" && |
|
701 type != "attributes", "Multiple reading of section."); |
|
702 _sections.insert(std::make_pair(type, |
|
703 new _reader_bits::LineSection<Functor>(functor))); |
|
704 return *this; |
|
705 } |
|
706 |
|
707 |
|
708 /// \brief Add a section processor with stream oriented reading |
|
709 /// |
|
710 /// In the \e LGF file extra sections can be placed, which contain |
|
711 /// any data in arbitrary format. These sections can be read |
|
712 /// directly with this function. The first parameter is the type |
|
713 /// of the section, the second is a functor, which takes an \c |
|
714 /// std::istream& and an int& parameter, the latter regard to the |
|
715 /// line number of stream. The functor can read the input while |
|
716 /// the section go on, and the line number should be modified |
|
717 /// accordingly. |
|
718 template <typename Functor> |
|
719 DigraphReader& sectionStream(const std::string& type, Functor functor) { |
|
720 LEMON_ASSERT(!type.empty(), "Type is not empty."); |
|
721 LEMON_ASSERT(_sections.find(type) == _sections.end(), |
|
722 "Multiple reading of section."); |
|
723 LEMON_ASSERT(type != "nodes" && type != "arcs" && type != "edges" && |
|
724 type != "attributes", "Multiple reading of section."); |
|
725 _sections.insert(std::make_pair(type, |
|
726 new _reader_bits::StreamSection<Functor>(functor))); |
|
727 return *this; |
|
728 } |
|
729 |
575 /// @} |
730 /// @} |
576 |
731 |
577 /// \name Using previously constructed node or arc set |
732 /// \name Using previously constructed node or arc set |
578 /// @{ |
733 /// @{ |
579 |
734 |
960 if (_attributes_caption.empty() || _attributes_caption == caption) { |
1116 if (_attributes_caption.empty() || _attributes_caption == caption) { |
961 readAttributes(); |
1117 readAttributes(); |
962 attributes_done = true; |
1118 attributes_done = true; |
963 } |
1119 } |
964 } else { |
1120 } else { |
965 readLine(); |
1121 if (extra_sections.find(section) != extra_sections.end()) { |
966 skipSection(); |
1122 std::ostringstream msg; |
|
1123 msg << "Multiple occurence of section " << section; |
|
1124 throw DataFormatError(msg.str().c_str()); |
|
1125 } |
|
1126 Sections::iterator it = _sections.find(section); |
|
1127 if (it != _sections.end()) { |
|
1128 extra_sections.insert(section); |
|
1129 it->second->process(*_is, line_num); |
|
1130 readLine(); |
|
1131 } else { |
|
1132 readLine(); |
|
1133 skipSection(); |
|
1134 } |
967 } |
1135 } |
968 } catch (DataFormatError& error) { |
1136 } catch (DataFormatError& error) { |
969 error.line(line_num); |
1137 error.line(line_num); |
970 throw; |
1138 throw; |
971 } |
1139 } |