Changeset 189:a63ed81c57ba in lemon-main
- Timestamp:
- 07/04/08 15:21:48 (16 years ago)
- Branch:
- default
- Phase:
- public
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
lemon/lgf_reader.h
r188 r189 420 420 /// proper type. If a section has an optional name, then it can be 421 421 /// 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. 425 423 /// 426 424 /// The \c useNodes() and \c useArcs() functions are used to tell the reader … … 474 472 Attributes _attributes; 475 473 476 typedef std::map<std::string, _reader_bits::Section*> Sections;477 Sections _sections;478 479 474 bool _use_nodes; 480 475 bool _use_arcs; … … 538 533 _attributes_caption = other._attributes_caption; 539 534 540 _sections.swap(other._sections);541 535 } 542 536 … … 555 549 for (typename Attributes::iterator it = _attributes.begin(); 556 550 it != _attributes.end(); ++it) { 557 delete it->second;558 }559 560 for (typename Sections::iterator it = _sections.begin();561 it != _sections.end(); ++it) {562 551 delete it->second; 563 552 } … … 707 696 } 708 697 709 /// @}710 711 /// \name Section readers712 /// @{713 714 /// \brief Add a section processor with line oriented reading715 ///716 /// In the \e LGF file extra sections can be placed, which contain717 /// any data in arbitrary format. These sections can be read with718 /// this function line by line. The first parameter is the type719 /// descriptor of the section, the second is a functor, which720 /// takes just one \c std::string parameter. At the reading721 /// process, each line of the section will be given to the functor722 /// object. However, the empty lines and the comment lines are723 /// filtered out, and the leading whitespaces are stipped from724 /// each processed string.725 ///726 /// For example let's see a section, which contain several727 /// integers, which should be inserted into a vector.728 ///\code729 /// @numbers730 /// 12 45 23731 /// 4732 /// 23 6733 ///\endcode734 ///735 /// The functor is implemented as an struct:736 ///\code737 /// 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 ///\endcode751 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 reading765 ///766 /// In the \e LGF file extra sections can be placed, which contain767 /// any data in arbitrary format. These sections can be read768 /// directly with this function. The first parameter is the type769 /// of the section, the second is a functor, which takes an \c770 /// std::istream& and an int& parameter, the latter regard to the771 /// line number of stream. The functor can read the input while772 /// the section go on, and the line number should be modified773 /// 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 786 698 /// @} 787 699 … … 1189 1101 bool arcs_done = _skip_arcs; 1190 1102 bool attributes_done = false; 1191 std::set<std::string> extra_sections;1192 1103 1193 1104 line_num = 0; … … 1223 1134 } 1224 1135 } 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 }1235 1136 readLine(); 1236 1137 skipSection(); … … 1296 1197 private: 1297 1198 1298 1299 1199 std::istream* _is; 1300 1200 bool local_is; … … 1322 1222 Attributes; 1323 1223 Attributes _attributes; 1324 1325 typedef std::map<std::string, _reader_bits::Section*> Sections;1326 Sections _sections;1327 1224 1328 1225 bool _use_nodes; … … 1387 1284 _attributes_caption = other._attributes_caption; 1388 1285 1389 _sections.swap(other._sections);1390 1286 } 1391 1287 … … 1404 1300 for (typename Attributes::iterator it = _attributes.begin(); 1405 1301 it != _attributes.end(); ++it) { 1406 delete it->second;1407 }1408 1409 for (typename Sections::iterator it = _sections.begin();1410 it != _sections.end(); ++it) {1411 1302 delete it->second; 1412 1303 } … … 1602 1493 } 1603 1494 1604 /// @}1605 1606 /// \name Section readers1607 /// @{1608 1609 /// \brief Add a section processor with line oriented reading1610 ///1611 /// In the \e LGF file extra sections can be placed, which contain1612 /// any data in arbitrary format. These sections can be read with1613 /// this function line by line. The first parameter is the type1614 /// descriptor of the section, the second is a functor, which1615 /// takes just one \c std::string parameter. At the reading1616 /// process, each line of the section will be given to the functor1617 /// object. However, the empty lines and the comment lines are1618 /// filtered out, and the leading whitespaces are stipped from1619 /// each processed string.1620 ///1621 /// For example let's see a section, which contain several1622 /// integers, which should be inserted into a vector.1623 ///\code1624 /// @numbers1625 /// 12 45 231626 /// 41627 /// 23 61628 ///\endcode1629 ///1630 /// The functor is implemented as an struct:1631 ///\code1632 /// 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 ///\endcode1646 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 reading1660 ///1661 /// In the \e LGF file extra sections can be placed, which contain1662 /// any data in arbitrary format. These sections can be read1663 /// directly with this function. The first parameter is the type1664 /// of the section, the second is a functor, which takes an \c1665 /// std::istream& and an int& parameter, the latter regard to the1666 /// line number of stream. The functor can read the input while1667 /// the section go on, and the line number should be modified1668 /// 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 1681 1495 /// @} 1682 1496 … … 2082 1896 bool edges_done = _skip_edges; 2083 1897 bool attributes_done = false; 2084 std::set<std::string> extra_sections;2085 1898 2086 1899 line_num = 0; … … 2116 1929 } 2117 1930 } 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 }2128 1931 readLine(); 2129 1932 skipSection(); … … 2172 1975 GraphReader<Graph> graphReader(const char* fn, Graph& graph) { 2173 1976 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); 2174 2224 return tmp; 2175 2225 }
Note: See TracChangeset
for help on using the changeset viewer.