704 DigraphReader& attributes(const std::string& caption) { |
693 DigraphReader& attributes(const std::string& caption) { |
705 _attributes_caption = caption; |
694 _attributes_caption = caption; |
706 return *this; |
695 return *this; |
707 } |
696 } |
708 |
697 |
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 |
|
786 /// @} |
698 /// @} |
787 |
699 |
788 /// \name Using previously constructed node or arc set |
700 /// \name Using previously constructed node or arc set |
789 /// @{ |
701 /// @{ |
790 |
702 |
1599 GraphReader& attributes(const std::string& caption) { |
1490 GraphReader& attributes(const std::string& caption) { |
1600 _attributes_caption = caption; |
1491 _attributes_caption = caption; |
1601 return *this; |
1492 return *this; |
1602 } |
1493 } |
1603 |
1494 |
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 |
|
1681 /// @} |
1495 /// @} |
1682 |
1496 |
1683 /// \name Using previously constructed node or edge set |
1497 /// \name Using previously constructed node or edge set |
1684 /// @{ |
1498 /// @{ |
1685 |
1499 |
2169 |
1972 |
2170 /// \relates GraphReader |
1973 /// \relates GraphReader |
2171 template <typename Graph> |
1974 template <typename Graph> |
2172 GraphReader<Graph> graphReader(const char* fn, Graph& graph) { |
1975 GraphReader<Graph> graphReader(const char* fn, Graph& graph) { |
2173 GraphReader<Graph> tmp(fn, graph); |
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 return tmp; |
2224 return tmp; |
2175 } |
2225 } |
2176 |
2226 |
2177 /// \ingroup lemon_io |
2227 /// \ingroup lemon_io |
2178 /// |
2228 /// |