| | 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 | |