COIN-OR::LEMON - Graph Library

Ticket #91: 94ebb18ab9c2.patch

File 94ebb18ab9c2.patch, 16.9 KB (added by Balazs Dezso, 12 years ago)
  • lemon/lgf_reader.h

    # HG changeset patch
    # User Balazs Dezso <deba@inf.elte.hu>
    # Date 1215094866 -7200
    # Node ID 94ebb18ab9c28e882cf393f099b2bc990ed7ff6c
    # Parent  70694e6bdcac801824ae907587fb5f9000dc6b9a
    Moving section readers to distinct class
    
    diff -r 70694e6bdcac -r 94ebb18ab9c2 lemon/lgf_reader.h
    a b  
    419419  /// By default the reader uses the first section in the file of the
    420420  /// proper type. If a section has an optional name, then it can be
    421421  /// selected for reading by giving an optional name parameter to the
    422   /// \c nodes(), \c arcs() or \c attributes() functions. The readers
    423   /// also can load extra sections with the \c sectionLines() and
    424   /// sectionStream() functions.
     422  /// \c nodes(), \c arcs() or \c attributes() functions.
    425423  ///
    426424  /// The \c useNodes() and \c useArcs() functions are used to tell the reader
    427425  /// that the nodes or arcs should not be constructed (added to the
     
    472470    typedef std::multimap<std::string, _reader_bits::ValueStorageBase*>
    473471      Attributes;
    474472    Attributes _attributes;
    475 
    476     typedef std::map<std::string, _reader_bits::Section*> Sections;
    477     Sections _sections;
    478473
    479474    bool _use_nodes;
    480475    bool _use_arcs;
     
    537532      _arcs_caption = other._arcs_caption;
    538533      _attributes_caption = other._attributes_caption;
    539534
    540       _sections.swap(other._sections);
    541535    }
    542536
    543537    /// \brief Destructor
     
    554548
    555549      for (typename Attributes::iterator it = _attributes.begin();
    556550           it != _attributes.end(); ++it) {
    557         delete it->second;
    558       }
    559 
    560       for (typename Sections::iterator it = _sections.begin();
    561            it != _sections.end(); ++it) {
    562551        delete it->second;
    563552      }
    564553
     
    706695      return *this;
    707696    }
    708697
    709     /// @}
    710 
    711     /// \name Section readers
    712     /// @{
    713 
    714     /// \brief Add a section processor with line oriented reading
    715     ///
    716     /// In the \e LGF file extra sections can be placed, which contain
    717     /// any data in arbitrary format. These sections can be read with
    718     /// this function line by line. The first parameter is the type
    719     /// descriptor of the section, the second is a functor, which
    720     /// takes just one \c std::string parameter. At the reading
    721     /// process, each line of the section will be given to the functor
    722     /// object. However, the empty lines and the comment lines are
    723     /// filtered out, and the leading whitespaces are stipped from
    724     /// each processed string.
    725     ///
    726     /// For example let's see a section, which contain several
    727     /// integers, which should be inserted into a vector.
    728     ///\code
    729     ///  @numbers
    730     ///  12 45 23
    731     ///  4
    732     ///  23 6
    733     ///\endcode
    734     ///
    735     /// The functor is implemented as an struct:
    736     ///\code
    737     ///  struct NumberSection {
    738     ///    std::vector<int>& _data;
    739     ///    NumberSection(std::vector<int>& data) : _data(data) {}
    740     ///    void operator()(const std::string& line) {
    741     ///      std::istringstream ls(line);
    742     ///      int value;
    743     ///      while (ls >> value) _data.push_back(value);
    744     ///    }
    745     ///  };
    746     ///
    747     ///  // ...
    748     ///
    749     ///  reader.sectionLines("numbers", NumberSection(vec)); 
    750     ///\endcode
    751     template <typename Functor>
    752     DigraphReader& sectionLines(const std::string& type, Functor functor) {
    753       LEMON_ASSERT(!type.empty(), "Type is not empty.");
    754       LEMON_ASSERT(_sections.find(type) == _sections.end(),
    755                    "Multiple reading of section.");
    756       LEMON_ASSERT(type != "nodes" && type != "arcs" && type != "edges" &&
    757                    type != "attributes", "Multiple reading of section.");
    758       _sections.insert(std::make_pair(type,
    759         new _reader_bits::LineSection<Functor>(functor)));
    760       return *this;
    761     }
    762 
    763 
    764     /// \brief Add a section processor with stream oriented reading
    765     ///
    766     /// In the \e LGF file extra sections can be placed, which contain
    767     /// any data in arbitrary format. These sections can be read
    768     /// directly with this function. The first parameter is the type
    769     /// of the section, the second is a functor, which takes an \c
    770     /// std::istream& and an int& parameter, the latter regard to the
    771     /// line number of stream. The functor can read the input while
    772     /// the section go on, and the line number should be modified
    773     /// accordingly.
    774     template <typename Functor>
    775     DigraphReader& sectionStream(const std::string& type, Functor functor) {
    776       LEMON_ASSERT(!type.empty(), "Type is not empty.");
    777       LEMON_ASSERT(_sections.find(type) == _sections.end(),
    778                    "Multiple reading of section.");
    779       LEMON_ASSERT(type != "nodes" && type != "arcs" && type != "edges" &&
    780                    type != "attributes", "Multiple reading of section.");
    781       _sections.insert(std::make_pair(type,
    782          new _reader_bits::StreamSection<Functor>(functor)));
    783       return *this;
    784     }   
    785    
    786698    /// @}
    787699
    788700    /// \name Using previously constructed node or arc set
     
    11881100      bool nodes_done = _skip_nodes;
    11891101      bool arcs_done = _skip_arcs;
    11901102      bool attributes_done = false;
    1191       std::set<std::string> extra_sections;
    11921103
    11931104      line_num = 0;     
    11941105      readLine();
     
    12221133              attributes_done = true;
    12231134            }
    12241135          } else {
    1225             if (extra_sections.find(section) != extra_sections.end()) {
    1226               std::ostringstream msg;
    1227               msg << "Multiple occurence of section " << section;
    1228               throw DataFormatError(msg.str().c_str());
    1229             }
    1230             Sections::iterator it = _sections.find(section);
    1231             if (it != _sections.end()) {
    1232               extra_sections.insert(section);
    1233               it->second->process(*_is, line_num);
    1234             }
    12351136            readLine();
    12361137            skipSection();
    12371138          }
     
    12951196   
    12961197  private:
    12971198
    1298 
    12991199    std::istream* _is;
    13001200    bool local_is;
    13011201
     
    13211221    typedef std::multimap<std::string, _reader_bits::ValueStorageBase*>
    13221222      Attributes;
    13231223    Attributes _attributes;
    1324 
    1325     typedef std::map<std::string, _reader_bits::Section*> Sections;
    1326     Sections _sections;
    13271224
    13281225    bool _use_nodes;
    13291226    bool _use_edges;
     
    13861283      _edges_caption = other._edges_caption;
    13871284      _attributes_caption = other._attributes_caption;
    13881285
    1389       _sections.swap(other._sections);
    13901286    }
    13911287
    13921288    /// \brief Destructor
     
    14031299
    14041300      for (typename Attributes::iterator it = _attributes.begin();
    14051301           it != _attributes.end(); ++it) {
    1406         delete it->second;
    1407       }
    1408 
    1409       for (typename Sections::iterator it = _sections.begin();
    1410            it != _sections.end(); ++it) {
    14111302        delete it->second;
    14121303      }
    14131304
     
    16011492      return *this;
    16021493    }
    16031494
    1604     /// @}
    1605 
    1606     /// \name Section readers
    1607     /// @{
    1608 
    1609     /// \brief Add a section processor with line oriented reading
    1610     ///
    1611     /// In the \e LGF file extra sections can be placed, which contain
    1612     /// any data in arbitrary format. These sections can be read with
    1613     /// this function line by line. The first parameter is the type
    1614     /// descriptor of the section, the second is a functor, which
    1615     /// takes just one \c std::string parameter. At the reading
    1616     /// process, each line of the section will be given to the functor
    1617     /// object. However, the empty lines and the comment lines are
    1618     /// filtered out, and the leading whitespaces are stipped from
    1619     /// each processed string.
    1620     ///
    1621     /// For example let's see a section, which contain several
    1622     /// integers, which should be inserted into a vector.
    1623     ///\code
    1624     ///  @numbers
    1625     ///  12 45 23
    1626     ///  4
    1627     ///  23 6
    1628     ///\endcode
    1629     ///
    1630     /// The functor is implemented as an struct:
    1631     ///\code
    1632     ///  struct NumberSection {
    1633     ///    std::vector<int>& _data;
    1634     ///    NumberSection(std::vector<int>& data) : _data(data) {}
    1635     ///    void operator()(const std::string& line) {
    1636     ///      std::istringstream ls(line);
    1637     ///      int value;
    1638     ///      while (ls >> value) _data.push_back(value);
    1639     ///    }
    1640     ///  };
    1641     ///
    1642     ///  // ...
    1643     ///
    1644     ///  reader.sectionLines("numbers", NumberSection(vec)); 
    1645     ///\endcode
    1646     template <typename Functor>
    1647     GraphReader& sectionLines(const std::string& type, Functor functor) {
    1648       LEMON_ASSERT(!type.empty(), "Type is not empty.");
    1649       LEMON_ASSERT(_sections.find(type) == _sections.end(),
    1650                    "Multiple reading of section.");
    1651       LEMON_ASSERT(type != "nodes" && type != "arcs" && type != "edges" &&
    1652                    type != "attributes", "Multiple reading of section.");
    1653       _sections.insert(std::make_pair(type,
    1654         new _reader_bits::LineSection<Functor>(functor)));
    1655       return *this;
    1656     }
    1657 
    1658 
    1659     /// \brief Add a section processor with stream oriented reading
    1660     ///
    1661     /// In the \e LGF file extra sections can be placed, which contain
    1662     /// any data in arbitrary format. These sections can be read
    1663     /// directly with this function. The first parameter is the type
    1664     /// of the section, the second is a functor, which takes an \c
    1665     /// std::istream& and an int& parameter, the latter regard to the
    1666     /// line number of stream. The functor can read the input while
    1667     /// the section go on, and the line number should be modified
    1668     /// accordingly.
    1669     template <typename Functor>
    1670     GraphReader& sectionStream(const std::string& type, Functor functor) {
    1671       LEMON_ASSERT(!type.empty(), "Type is not empty.");
    1672       LEMON_ASSERT(_sections.find(type) == _sections.end(),
    1673                    "Multiple reading of section.");
    1674       LEMON_ASSERT(type != "nodes" && type != "arcs" && type != "edges" &&
    1675                    type != "attributes", "Multiple reading of section.");
    1676       _sections.insert(std::make_pair(type,
    1677          new _reader_bits::StreamSection<Functor>(functor)));
    1678       return *this;
    1679     }   
    1680    
    16811495    /// @}
    16821496
    16831497    /// \name Using previously constructed node or edge set
     
    20811895      bool nodes_done = _skip_nodes;
    20821896      bool edges_done = _skip_edges;
    20831897      bool attributes_done = false;
    2084       std::set<std::string> extra_sections;
    20851898
    20861899      line_num = 0;     
    20871900      readLine();
     
    21151928              attributes_done = true;
    21161929            }
    21171930          } else {
    2118             if (extra_sections.find(section) != extra_sections.end()) {
    2119               std::ostringstream msg;
    2120               msg << "Multiple occurence of section " << section;
    2121               throw DataFormatError(msg.str().c_str());
    2122             }
    2123             Sections::iterator it = _sections.find(section);
    2124             if (it != _sections.end()) {
    2125               extra_sections.insert(section);
    2126               it->second->process(*_is, line_num);
    2127             }
    21281931            readLine();
    21291932            skipSection();
    21301933          }
     
    21731976    GraphReader<Graph> tmp(fn, graph);
    21741977    return tmp;
    21751978  }
     1979
     1980  /// \brief Section reader class
     1981  ///
     1982  /// In the \e LGF file extra sections can be placed, which contain
     1983  /// any data in arbitrary format. Such sections can be read with
     1984  /// this class. A reading rule can be added with two different
     1985  /// functions, with the \c sectionLines() function a functor can
     1986  /// process the section line-by-line. While with the \c
     1987  /// sectionStream() member the section can be read from an input
     1988  /// stream.
     1989  class SectionReader {
     1990  private:
     1991   
     1992    std::istream* _is;
     1993    bool local_is;
     1994
     1995    typedef std::map<std::string, _reader_bits::Section*> Sections;
     1996    Sections _sections;
     1997
     1998    int line_num;
     1999    std::istringstream line;
     2000
     2001  public:
     2002
     2003    /// \brief Constructor
     2004    ///
     2005    /// Construct a section reader, which reads from the given input
     2006    /// stream.
     2007    SectionReader(std::istream& is)
     2008      : _is(&is), local_is(false) {}
     2009
     2010    /// \brief Constructor
     2011    ///
     2012    /// Construct a section reader, which reads from the given file.
     2013    SectionReader(const std::string& fn)
     2014      : _is(new std::ifstream(fn.c_str())), local_is(true) {}
     2015   
     2016    /// \brief Constructor
     2017    ///
     2018    /// Construct a section reader, which reads from the given file.
     2019    SectionReader(const char* fn)
     2020      : _is(new std::ifstream(fn)), local_is(true) {}
     2021
     2022    /// \brief Copy constructor
     2023    ///
     2024    /// The copy constructor transfers all data from the other reader,
     2025    /// therefore the copied reader will not be usable more.
     2026    SectionReader(SectionReader& other)
     2027      : _is(other._is), local_is(other.local_is) {
     2028
     2029      other._is = 0;
     2030      other.local_is = false;
     2031     
     2032      _sections.swap(other._sections);
     2033    }
     2034
     2035    /// \brief Destructor
     2036    ~SectionReader() {
     2037      for (Sections::iterator it = _sections.begin();
     2038           it != _sections.end(); ++it) {
     2039        delete it->second;
     2040      }
     2041
     2042      if (local_is) {
     2043        delete _is;
     2044      }
     2045
     2046    }
     2047
     2048    /// \name Section readers
     2049    /// @{
     2050
     2051    /// \brief Add a section processor with line oriented reading
     2052    ///
     2053    /// The first parameter is the type descriptor of the section, the
     2054    /// second is a functor, which takes just one \c std::string
     2055    /// parameter. At the reading process, each line of the section
     2056    /// will be given to the functor object. However, the empty lines
     2057    /// and the comment lines are filtered out, and the leading
     2058    /// whitespaces are trimmed from each processed string.
     2059    ///
     2060    /// For example let's see a section, which contain several
     2061    /// integers, which should be inserted into a vector.
     2062    ///\code
     2063    ///  @numbers
     2064    ///  12 45 23
     2065    ///  4
     2066    ///  23 6
     2067    ///\endcode
     2068    ///
     2069    /// The functor is implemented as an struct:
     2070    ///\code
     2071    ///  struct NumberSection {
     2072    ///    std::vector<int>& _data;
     2073    ///    NumberSection(std::vector<int>& data) : _data(data) {}
     2074    ///    void operator()(const std::string& line) {
     2075    ///      std::istringstream ls(line);
     2076    ///      int value;
     2077    ///      while (ls >> value) _data.push_back(value);
     2078    ///    }
     2079    ///  };
     2080    ///
     2081    ///  // ...
     2082    ///
     2083    ///  reader.sectionLines("numbers", NumberSection(vec)); 
     2084    ///\endcode
     2085    template <typename Functor>
     2086    SectionReader& sectionLines(const std::string& type, Functor functor) {
     2087      LEMON_ASSERT(!type.empty(), "Type is not empty.");
     2088      LEMON_ASSERT(_sections.find(type) == _sections.end(),
     2089                   "Multiple reading of section.");
     2090      _sections.insert(std::make_pair(type,
     2091        new _reader_bits::LineSection<Functor>(functor)));
     2092      return *this;
     2093    }
     2094
     2095
     2096    /// \brief Add a section processor with stream oriented reading
     2097    ///
     2098    /// The first parameter is the type of the section, the second is
     2099    /// a functor, which takes an \c std::istream& and an int&
     2100    /// parameter, the latter regard to the line number of stream. The
     2101    /// functor can read the input while the section go on, and the
     2102    /// line number should be modified accordingly.
     2103    template <typename Functor>
     2104    SectionReader& sectionStream(const std::string& type, Functor functor) {
     2105      LEMON_ASSERT(!type.empty(), "Type is not empty.");
     2106      LEMON_ASSERT(_sections.find(type) == _sections.end(),
     2107                   "Multiple reading of section.");
     2108      _sections.insert(std::make_pair(type,
     2109         new _reader_bits::StreamSection<Functor>(functor)));
     2110      return *this;
     2111    }   
     2112   
     2113    /// @}
     2114
     2115  private:
     2116
     2117    bool readLine() {
     2118      std::string str;
     2119      while(++line_num, std::getline(*_is, str)) {
     2120        line.clear(); line.str(str);
     2121        char c;
     2122        if (line >> std::ws >> c && c != '#') {
     2123          line.putback(c);
     2124          return true;
     2125        }
     2126      }
     2127      return false;
     2128    }
     2129
     2130    bool readSuccess() {
     2131      return static_cast<bool>(*_is);
     2132    }
     2133   
     2134    void skipSection() {
     2135      char c;
     2136      while (readSuccess() && line >> c && c != '@') {
     2137        readLine();
     2138      }
     2139      line.putback(c);
     2140    }
     2141
     2142  public:
     2143
     2144
     2145    /// \name Execution of the reader   
     2146    /// @{
     2147
     2148    /// \brief Start the batch processing
     2149    ///
     2150    /// This function starts the batch processing
     2151    void run() {
     2152     
     2153      LEMON_ASSERT(_is != 0, "This reader assigned to an other reader");
     2154     
     2155      std::set<std::string> extra_sections;
     2156
     2157      line_num = 0;     
     2158      readLine();
     2159      skipSection();
     2160
     2161      while (readSuccess()) {
     2162        try {
     2163          char c;
     2164          std::string section, caption;
     2165          line >> c;
     2166          _reader_bits::readToken(line, section);
     2167          _reader_bits::readToken(line, caption);
     2168
     2169          if (line >> c)
     2170            throw DataFormatError("Extra character on the end of line");
     2171
     2172          if (extra_sections.find(section) != extra_sections.end()) {
     2173            std::ostringstream msg;
     2174            msg << "Multiple occurence of section " << section;
     2175            throw DataFormatError(msg.str().c_str());
     2176          }
     2177          Sections::iterator it = _sections.find(section);
     2178          if (it != _sections.end()) {
     2179            extra_sections.insert(section);
     2180            it->second->process(*_is, line_num);
     2181          }
     2182          readLine();
     2183          skipSection();
     2184        } catch (DataFormatError& error) {
     2185          error.line(line_num);
     2186          throw;
     2187        }       
     2188      }
     2189      for (Sections::iterator it = _sections.begin();
     2190           it != _sections.end(); ++it) {
     2191        if (extra_sections.find(it->first) == extra_sections.end()) {
     2192          std::ostringstream os;
     2193          os << "Cannot find section: " << it->first;
     2194          throw DataFormatError(os.str().c_str());
     2195        }
     2196      }
     2197    }
     2198
     2199    /// @}
     2200   
     2201   
     2202  };
    21762203
    21772204  /// \ingroup lemon_io
    21782205  ///