COIN-OR::LEMON - Graph Library

Ticket #91: a63ed81c57ba.patch

File a63ed81c57ba.patch, 17.5 KB (added by Balazs Dezso, 16 years ago)
  • lemon/lgf_reader.h

    # HG changeset patch
    # User Balazs Dezso <deba@inf.elte.hu>
    # Date 1215177708 -7200
    # Node ID a63ed81c57babfd26265bcf154436fb8600c13c3
    # Parent  70694e6bdcac801824ae907587fb5f9000dc6b9a
    Section readers moved to distinct class
    
    diff -r 70694e6bdcac -r a63ed81c57ba 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          }
     
    21711974  template <typename Graph>
    21721975  GraphReader<Graph> graphReader(const char* fn, Graph& graph) {
    21731976    GraphReader<Graph> tmp(fn, graph);
     1977    return tmp;
     1978  }
     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  private:
     2049   
     2050    SectionReader& operator=(const SectionReader&);
     2051
     2052  public:
     2053
     2054    /// \name Section readers
     2055    /// @{
     2056
     2057    /// \brief Add a section processor with line oriented reading
     2058    ///
     2059    /// The first parameter is the type descriptor of the section, the
     2060    /// second is a functor, which takes just one \c std::string
     2061    /// parameter. At the reading process, each line of the section
     2062    /// will be given to the functor object. However, the empty lines
     2063    /// and the comment lines are filtered out, and the leading
     2064    /// whitespaces are trimmed from each processed string.
     2065    ///
     2066    /// For example let's see a section, which contain several
     2067    /// integers, which should be inserted into a vector.
     2068    ///\code
     2069    ///  @numbers
     2070    ///  12 45 23
     2071    ///  4
     2072    ///  23 6
     2073    ///\endcode
     2074    ///
     2075    /// The functor is implemented as an struct:
     2076    ///\code
     2077    ///  struct NumberSection {
     2078    ///    std::vector<int>& _data;
     2079    ///    NumberSection(std::vector<int>& data) : _data(data) {}
     2080    ///    void operator()(const std::string& line) {
     2081    ///      std::istringstream ls(line);
     2082    ///      int value;
     2083    ///      while (ls >> value) _data.push_back(value);
     2084    ///    }
     2085    ///  };
     2086    ///
     2087    ///  // ...
     2088    ///
     2089    ///  reader.sectionLines("numbers", NumberSection(vec)); 
     2090    ///\endcode
     2091    template <typename Functor>
     2092    SectionReader& sectionLines(const std::string& type, Functor functor) {
     2093      LEMON_ASSERT(!type.empty(), "Type is not empty.");
     2094      LEMON_ASSERT(_sections.find(type) == _sections.end(),
     2095                   "Multiple reading of section.");
     2096      _sections.insert(std::make_pair(type,
     2097        new _reader_bits::LineSection<Functor>(functor)));
     2098      return *this;
     2099    }
     2100
     2101
     2102    /// \brief Add a section processor with stream oriented reading
     2103    ///
     2104    /// The first parameter is the type of the section, the second is
     2105    /// a functor, which takes an \c std::istream& and an int&
     2106    /// parameter, the latter regard to the line number of stream. The
     2107    /// functor can read the input while the section go on, and the
     2108    /// line number should be modified accordingly.
     2109    template <typename Functor>
     2110    SectionReader& sectionStream(const std::string& type, Functor functor) {
     2111      LEMON_ASSERT(!type.empty(), "Type is not empty.");
     2112      LEMON_ASSERT(_sections.find(type) == _sections.end(),
     2113                   "Multiple reading of section.");
     2114      _sections.insert(std::make_pair(type,
     2115         new _reader_bits::StreamSection<Functor>(functor)));
     2116      return *this;
     2117    }   
     2118   
     2119    /// @}
     2120
     2121  private:
     2122
     2123    bool readLine() {
     2124      std::string str;
     2125      while(++line_num, std::getline(*_is, str)) {
     2126        line.clear(); line.str(str);
     2127        char c;
     2128        if (line >> std::ws >> c && c != '#') {
     2129          line.putback(c);
     2130          return true;
     2131        }
     2132      }
     2133      return false;
     2134    }
     2135
     2136    bool readSuccess() {
     2137      return static_cast<bool>(*_is);
     2138    }
     2139   
     2140    void skipSection() {
     2141      char c;
     2142      while (readSuccess() && line >> c && c != '@') {
     2143        readLine();
     2144      }
     2145      line.putback(c);
     2146    }
     2147
     2148  public:
     2149
     2150
     2151    /// \name Execution of the reader   
     2152    /// @{
     2153
     2154    /// \brief Start the batch processing
     2155    ///
     2156    /// This function starts the batch processing
     2157    void run() {
     2158     
     2159      LEMON_ASSERT(_is != 0, "This reader assigned to an other reader");
     2160     
     2161      std::set<std::string> extra_sections;
     2162
     2163      line_num = 0;     
     2164      readLine();
     2165      skipSection();
     2166
     2167      while (readSuccess()) {
     2168        try {
     2169          char c;
     2170          std::string section, caption;
     2171          line >> c;
     2172          _reader_bits::readToken(line, section);
     2173          _reader_bits::readToken(line, caption);
     2174
     2175          if (line >> c)
     2176            throw DataFormatError("Extra character on the end of line");
     2177
     2178          if (extra_sections.find(section) != extra_sections.end()) {
     2179            std::ostringstream msg;
     2180            msg << "Multiple occurence of section " << section;
     2181            throw DataFormatError(msg.str().c_str());
     2182          }
     2183          Sections::iterator it = _sections.find(section);
     2184          if (it != _sections.end()) {
     2185            extra_sections.insert(section);
     2186            it->second->process(*_is, line_num);
     2187          }
     2188          readLine();
     2189          skipSection();
     2190        } catch (DataFormatError& error) {
     2191          error.line(line_num);
     2192          throw;
     2193        }       
     2194      }
     2195      for (Sections::iterator it = _sections.begin();
     2196           it != _sections.end(); ++it) {
     2197        if (extra_sections.find(it->first) == extra_sections.end()) {
     2198          std::ostringstream os;
     2199          os << "Cannot find section: " << it->first;
     2200          throw DataFormatError(os.str().c_str());
     2201        }
     2202      }
     2203    }
     2204
     2205    /// @}
     2206       
     2207  };
     2208
     2209  /// \relates SectionReader
     2210  inline SectionReader sectionReader(std::istream& is) {
     2211    SectionReader tmp(is);
     2212    return tmp;
     2213  }
     2214
     2215  /// \relates SectionReader
     2216  inline SectionReader sectionReader(const std::string& fn) {
     2217    SectionReader tmp(fn);
     2218    return tmp;
     2219  }
     2220
     2221  /// \relates SectionReader
     2222  inline SectionReader sectionReader(const char* fn) {
     2223    SectionReader tmp(fn);
    21742224    return tmp;
    21752225  }
    21762226