1.1 --- a/lemon/lgf_reader.h Mon May 26 13:50:47 2008 +0100
1.2 +++ b/lemon/lgf_reader.h Tue May 27 16:01:20 2008 +0200
1.3 @@ -268,6 +268,72 @@
1.4 str = os.str();
1.5 return is;
1.6 }
1.7 +
1.8 + class Section {
1.9 + public:
1.10 + virtual ~Section() {}
1.11 + virtual void process(std::istream& is, int& line_num) = 0;
1.12 + };
1.13 +
1.14 + template <typename Functor>
1.15 + class LineSection : public Section {
1.16 + private:
1.17 +
1.18 + Functor _functor;
1.19 +
1.20 + public:
1.21 +
1.22 + LineSection(const Functor& functor) : _functor(functor) {}
1.23 + virtual ~LineSection() {}
1.24 +
1.25 + virtual void process(std::istream& is, int& line_num) {
1.26 + char c;
1.27 + std::string line;
1.28 + while (is.get(c) && c != '@') {
1.29 + if (c == '\n') {
1.30 + ++line_num;
1.31 + } else if (c == '#') {
1.32 + getline(is, line);
1.33 + ++line_num;
1.34 + } else if (!isWhiteSpace(c)) {
1.35 + is.putback(c);
1.36 + getline(is, line);
1.37 + _functor(line);
1.38 + ++line_num;
1.39 + }
1.40 + }
1.41 + if (is) is.putback(c);
1.42 + else if (is.eof()) is.clear();
1.43 + }
1.44 + };
1.45 +
1.46 + template <typename Functor>
1.47 + class StreamSection : public Section {
1.48 + private:
1.49 +
1.50 + Functor _functor;
1.51 +
1.52 + public:
1.53 +
1.54 + StreamSection(const Functor& functor) : _functor(functor) {}
1.55 + virtual ~StreamSection() {}
1.56 +
1.57 + virtual void process(std::istream& is, int& line_num) {
1.58 + _functor(is, line_num);
1.59 + char c;
1.60 + std::string line;
1.61 + while (is.get(c) && c != '@') {
1.62 + if (c == '\n') {
1.63 + ++line_num;
1.64 + } else if (!isWhiteSpace(c)) {
1.65 + getline(is, line);
1.66 + ++line_num;
1.67 + }
1.68 + }
1.69 + if (is) is.putback(c);
1.70 + else if (is.eof()) is.clear();
1.71 + }
1.72 + };
1.73
1.74 }
1.75
1.76 @@ -282,13 +348,14 @@
1.77 /// reader, and eventually the reading is executed with the \c run()
1.78 /// member function. A map reading rule can be added to the reader
1.79 /// with the \c nodeMap() or \c arcMap() members. An optional
1.80 - /// converter parameter can also be added as a standard functor converting from
1.81 - /// std::string to the value type of the map. If it is set, it will
1.82 - /// determine how the tokens in the file should be is converted to the map's
1.83 - /// value type. If the functor is not set, then a default conversion
1.84 - /// will be used. One map can be read into multiple map objects at the
1.85 - /// same time. The \c attribute(), \c node() and \c arc() functions
1.86 - /// are used to add attribute reading rules.
1.87 + /// converter parameter can also be added as a standard functor
1.88 + /// converting from std::string to the value type of the map. If it
1.89 + /// is set, it will determine how the tokens in the file should be
1.90 + /// is converted to the map's value type. If the functor is not set,
1.91 + /// then a default conversion will be used. One map can be read into
1.92 + /// multiple map objects at the same time. The \c attribute(), \c
1.93 + /// node() and \c arc() functions are used to add attribute reading
1.94 + /// rules.
1.95 ///
1.96 ///\code
1.97 /// DigraphReader<Digraph>(std::cin, digraph).
1.98 @@ -302,9 +369,10 @@
1.99 ///
1.100 /// By default the reader uses the first section in the file of the
1.101 /// proper type. If a section has an optional name, then it can be
1.102 - /// selected for reading by giving an optional name parameter to
1.103 - /// the \c nodes(), \c arcs() or \c attributes()
1.104 - /// functions.
1.105 + /// selected for reading by giving an optional name parameter to the
1.106 + /// \c nodes(), \c arcs() or \c attributes() functions. The readers
1.107 + /// also can load extra sections with the \c sectionLines() and
1.108 + /// sectionStream() functions.
1.109 ///
1.110 /// The \c useNodes() and \c useArcs() functions are used to tell the reader
1.111 /// that the nodes or arcs should not be constructed (added to the
1.112 @@ -356,6 +424,9 @@
1.113 Attributes;
1.114 Attributes _attributes;
1.115
1.116 + typedef std::map<std::string, _reader_bits::Section*> Sections;
1.117 + Sections _sections;
1.118 +
1.119 bool _use_nodes;
1.120 bool _use_arcs;
1.121
1.122 @@ -409,6 +480,8 @@
1.123 _nodes_caption = other._nodes_caption;
1.124 _arcs_caption = other._arcs_caption;
1.125 _attributes_caption = other._attributes_caption;
1.126 +
1.127 + _sections.swap(other._sections);
1.128 }
1.129
1.130 /// \brief Destructor
1.131 @@ -428,6 +501,11 @@
1.132 delete it->second;
1.133 }
1.134
1.135 + for (typename Sections::iterator it = _sections.begin();
1.136 + it != _sections.end(); ++it) {
1.137 + delete it->second;
1.138 + }
1.139 +
1.140 if (local_is) {
1.141 delete _is;
1.142 }
1.143 @@ -574,6 +652,83 @@
1.144
1.145 /// @}
1.146
1.147 + /// \name Section readers
1.148 + /// @{
1.149 +
1.150 + /// \brief Add a section processor with line oriented reading
1.151 + ///
1.152 + /// In the \e LGF file extra sections can be placed, which contain
1.153 + /// any data in arbitrary format. These sections can be read with
1.154 + /// this function line by line. The first parameter is the type
1.155 + /// descriptor of the section, the second is a functor, which
1.156 + /// takes just one \c std::string parameter. At the reading
1.157 + /// process, each line of the section will be given to the functor
1.158 + /// object. However, the empty lines and the comment lines are
1.159 + /// filtered out, and the leading whitespaces are stipped from
1.160 + /// each processed string.
1.161 + ///
1.162 + /// For example let's see a section, which contain several
1.163 + /// integers, which should be inserted into a vector.
1.164 + ///\code
1.165 + /// @numbers
1.166 + /// 12 45 23
1.167 + /// 4
1.168 + /// 23 6
1.169 + ///\endcode
1.170 + ///
1.171 + /// The functor is implemented as an struct:
1.172 + ///\code
1.173 + /// struct NumberSection {
1.174 + /// std::vector<int>& _data;
1.175 + /// NumberSection(std::vector<int>& data) : _data(data) {}
1.176 + /// void operator()(const std::string& line) {
1.177 + /// std::istringstream ls(line);
1.178 + /// int value;
1.179 + /// while (ls >> value) _data.push_back(value);
1.180 + /// }
1.181 + /// };
1.182 + ///
1.183 + /// // ...
1.184 + ///
1.185 + /// reader.sectionLines("numbers", NumberSection(vec));
1.186 + ///\endcode
1.187 + template <typename Functor>
1.188 + DigraphReader& sectionLines(const std::string& type, Functor functor) {
1.189 + LEMON_ASSERT(!type.empty(), "Type is not empty.");
1.190 + LEMON_ASSERT(_sections.find(type) == _sections.end(),
1.191 + "Multiple reading of section.");
1.192 + LEMON_ASSERT(type != "nodes" && type != "arcs" && type != "edges" &&
1.193 + type != "attributes", "Multiple reading of section.");
1.194 + _sections.insert(std::make_pair(type,
1.195 + new _reader_bits::LineSection<Functor>(functor)));
1.196 + return *this;
1.197 + }
1.198 +
1.199 +
1.200 + /// \brief Add a section processor with stream oriented reading
1.201 + ///
1.202 + /// In the \e LGF file extra sections can be placed, which contain
1.203 + /// any data in arbitrary format. These sections can be read
1.204 + /// directly with this function. The first parameter is the type
1.205 + /// of the section, the second is a functor, which takes an \c
1.206 + /// std::istream& and an int& parameter, the latter regard to the
1.207 + /// line number of stream. The functor can read the input while
1.208 + /// the section go on, and the line number should be modified
1.209 + /// accordingly.
1.210 + template <typename Functor>
1.211 + DigraphReader& sectionStream(const std::string& type, Functor functor) {
1.212 + LEMON_ASSERT(!type.empty(), "Type is not empty.");
1.213 + LEMON_ASSERT(_sections.find(type) == _sections.end(),
1.214 + "Multiple reading of section.");
1.215 + LEMON_ASSERT(type != "nodes" && type != "arcs" && type != "edges" &&
1.216 + type != "attributes", "Multiple reading of section.");
1.217 + _sections.insert(std::make_pair(type,
1.218 + new _reader_bits::StreamSection<Functor>(functor)));
1.219 + return *this;
1.220 + }
1.221 +
1.222 + /// @}
1.223 +
1.224 /// \name Using previously constructed node or arc set
1.225 /// @{
1.226
1.227 @@ -929,6 +1084,7 @@
1.228 bool nodes_done = false;
1.229 bool arcs_done = false;
1.230 bool attributes_done = false;
1.231 + std::set<std::string> extra_sections;
1.232
1.233 line_num = 0;
1.234 readLine();
1.235 @@ -962,8 +1118,20 @@
1.236 attributes_done = true;
1.237 }
1.238 } else {
1.239 - readLine();
1.240 - skipSection();
1.241 + if (extra_sections.find(section) != extra_sections.end()) {
1.242 + std::ostringstream msg;
1.243 + msg << "Multiple occurence of section " << section;
1.244 + throw DataFormatError(msg.str().c_str());
1.245 + }
1.246 + Sections::iterator it = _sections.find(section);
1.247 + if (it != _sections.end()) {
1.248 + extra_sections.insert(section);
1.249 + it->second->process(*_is, line_num);
1.250 + readLine();
1.251 + } else {
1.252 + readLine();
1.253 + skipSection();
1.254 + }
1.255 }
1.256 } catch (DataFormatError& error) {
1.257 error.line(line_num);