| 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 | }; |
285 | | /// converter parameter can also be added as a standard functor converting from |
286 | | /// std::string to the value type of the map. If it is set, it will |
287 | | /// determine how the tokens in the file should be is converted to the map's |
288 | | /// value type. If the functor is not set, then a default conversion |
289 | | /// will be used. One map can be read into multiple map objects at the |
290 | | /// same time. The \c attribute(), \c node() and \c arc() functions |
291 | | /// are used to add attribute reading rules. |
| 351 | /// converter parameter can also be added as a standard functor |
| 352 | /// converting from std::string to the value type of the map. If it |
| 353 | /// is set, it will determine how the tokens in the file should be |
| 354 | /// is converted to the map's value type. If the functor is not set, |
| 355 | /// then a default conversion will be used. One map can be read into |
| 356 | /// multiple map objects at the same time. The \c attribute(), \c |
| 357 | /// node() and \c arc() functions are used to add attribute reading |
| 358 | /// rules. |
| 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 | |