COIN-OR::LEMON - Graph Library

Ticket #91: section_reader.patch

File section_reader.patch, 9.0 KB (added by Balazs Dezso, 16 years ago)
  • doc/lgf.dox

    # HG changeset patch
    # User Balazs Dezso <deba@inf.elte.hu>
    # Date 1211896880 -7200
    # Node ID 33247f6fff166e4f31556176cd5c3b18627e6332
    # Parent  2c999941b871df96768c2c31a93507c9634cd288
    Section reader for DigraphReader
    
    diff -r 2c999941b871 -r 33247f6fff16 doc/lgf.dox
    a b  
    9090 caption "LEMON test digraph"
    9191\endcode
    9292
     93The \e LGF can contain extra sections, but there is no restriction on
     94the format of such sections.
     95
    9396*/
    9497}
    9598
  • lemon/lgf_reader.h

    diff -r 2c999941b871 -r 33247f6fff16 lemon/lgf_reader.h
    a b  
    268268      str = os.str();
    269269      return is;
    270270    }
     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    };
    271337   
    272338  }
    273339
     
    282348  /// reader, and eventually the reading is executed with the \c run()
    283349  /// member function. A map reading rule can be added to the reader
    284350  /// with the \c nodeMap() or \c arcMap() members. An optional
    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.
    292359  ///
    293360  ///\code
    294361  ///     DigraphReader<Digraph>(std::cin, digraph).
     
    302369  ///
    303370  /// By default the reader uses the first section in the file of the
    304371  /// proper type. If a section has an optional name, then it can be
    305   /// selected for reading by giving an optional name parameter to
    306   /// the \c nodes(), \c arcs() or \c attributes()
    307   /// functions.
     372  /// selected for reading by giving an optional name parameter to the
     373  /// \c nodes(), \c arcs() or \c attributes() functions. The readers
     374  /// also can load extra sections with the \c sectionLines() and
     375  /// sectionStream() functions.
    308376  ///
    309377  /// The \c useNodes() and \c useArcs() functions are used to tell the reader
    310378  /// that the nodes or arcs should not be constructed (added to the
     
    355423    typedef std::multimap<std::string, _reader_bits::ValueStorageBase*>
    356424      Attributes;
    357425    Attributes _attributes;
     426
     427    typedef std::map<std::string, _reader_bits::Section*> Sections;
     428    Sections _sections;
    358429
    359430    bool _use_nodes;
    360431    bool _use_arcs;
     
    409480      _nodes_caption = other._nodes_caption;
    410481      _arcs_caption = other._arcs_caption;
    411482      _attributes_caption = other._attributes_caption;
     483
     484      _sections.swap(other._sections);
    412485    }
    413486
    414487    /// \brief Destructor
     
    425498
    426499      for (typename Attributes::iterator it = _attributes.begin();
    427500           it != _attributes.end(); ++it) {
     501        delete it->second;
     502      }
     503
     504      for (typename Sections::iterator it = _sections.begin();
     505           it != _sections.end(); ++it) {
    428506        delete it->second;
    429507      }
    430508
     
    572650      return *this;
    573651    }
    574652
     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   
    575730    /// @}
    576731
    577732    /// \name Using previously constructed node or arc set
     
    9291084      bool nodes_done = false;
    9301085      bool arcs_done = false;
    9311086      bool attributes_done = false;
     1087      std::set<std::string> extra_sections;
    9321088
    9331089      line_num = 0;     
    9341090      readLine();
     
    9621118              attributes_done = true;
    9631119            }
    9641120          } else {
    965             readLine();
    966             skipSection();
     1121            if (extra_sections.find(section) != extra_sections.end()) {
     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            }
    9671135          }
    9681136        } catch (DataFormatError& error) {
    9691137          error.line(line_num);