1.1 --- a/lemon/lgf_reader.h Thu Jul 03 12:40:04 2008 +0200
1.2 +++ b/lemon/lgf_reader.h Fri Jul 04 15:21:48 2008 +0200
1.3 @@ -419,9 +419,7 @@
1.4 /// By default the reader uses the first section in the file of the
1.5 /// proper type. If a section has an optional name, then it can be
1.6 /// selected for reading by giving an optional name parameter to the
1.7 - /// \c nodes(), \c arcs() or \c attributes() functions. The readers
1.8 - /// also can load extra sections with the \c sectionLines() and
1.9 - /// sectionStream() functions.
1.10 + /// \c nodes(), \c arcs() or \c attributes() functions.
1.11 ///
1.12 /// The \c useNodes() and \c useArcs() functions are used to tell the reader
1.13 /// that the nodes or arcs should not be constructed (added to the
1.14 @@ -473,9 +471,6 @@
1.15 Attributes;
1.16 Attributes _attributes;
1.17
1.18 - typedef std::map<std::string, _reader_bits::Section*> Sections;
1.19 - Sections _sections;
1.20 -
1.21 bool _use_nodes;
1.22 bool _use_arcs;
1.23
1.24 @@ -537,7 +532,6 @@
1.25 _arcs_caption = other._arcs_caption;
1.26 _attributes_caption = other._attributes_caption;
1.27
1.28 - _sections.swap(other._sections);
1.29 }
1.30
1.31 /// \brief Destructor
1.32 @@ -557,11 +551,6 @@
1.33 delete it->second;
1.34 }
1.35
1.36 - for (typename Sections::iterator it = _sections.begin();
1.37 - it != _sections.end(); ++it) {
1.38 - delete it->second;
1.39 - }
1.40 -
1.41 if (local_is) {
1.42 delete _is;
1.43 }
1.44 @@ -708,83 +697,6 @@
1.45
1.46 /// @}
1.47
1.48 - /// \name Section readers
1.49 - /// @{
1.50 -
1.51 - /// \brief Add a section processor with line oriented reading
1.52 - ///
1.53 - /// In the \e LGF file extra sections can be placed, which contain
1.54 - /// any data in arbitrary format. These sections can be read with
1.55 - /// this function line by line. The first parameter is the type
1.56 - /// descriptor of the section, the second is a functor, which
1.57 - /// takes just one \c std::string parameter. At the reading
1.58 - /// process, each line of the section will be given to the functor
1.59 - /// object. However, the empty lines and the comment lines are
1.60 - /// filtered out, and the leading whitespaces are stipped from
1.61 - /// each processed string.
1.62 - ///
1.63 - /// For example let's see a section, which contain several
1.64 - /// integers, which should be inserted into a vector.
1.65 - ///\code
1.66 - /// @numbers
1.67 - /// 12 45 23
1.68 - /// 4
1.69 - /// 23 6
1.70 - ///\endcode
1.71 - ///
1.72 - /// The functor is implemented as an struct:
1.73 - ///\code
1.74 - /// struct NumberSection {
1.75 - /// std::vector<int>& _data;
1.76 - /// NumberSection(std::vector<int>& data) : _data(data) {}
1.77 - /// void operator()(const std::string& line) {
1.78 - /// std::istringstream ls(line);
1.79 - /// int value;
1.80 - /// while (ls >> value) _data.push_back(value);
1.81 - /// }
1.82 - /// };
1.83 - ///
1.84 - /// // ...
1.85 - ///
1.86 - /// reader.sectionLines("numbers", NumberSection(vec));
1.87 - ///\endcode
1.88 - template <typename Functor>
1.89 - DigraphReader& sectionLines(const std::string& type, Functor functor) {
1.90 - LEMON_ASSERT(!type.empty(), "Type is not empty.");
1.91 - LEMON_ASSERT(_sections.find(type) == _sections.end(),
1.92 - "Multiple reading of section.");
1.93 - LEMON_ASSERT(type != "nodes" && type != "arcs" && type != "edges" &&
1.94 - type != "attributes", "Multiple reading of section.");
1.95 - _sections.insert(std::make_pair(type,
1.96 - new _reader_bits::LineSection<Functor>(functor)));
1.97 - return *this;
1.98 - }
1.99 -
1.100 -
1.101 - /// \brief Add a section processor with stream oriented reading
1.102 - ///
1.103 - /// In the \e LGF file extra sections can be placed, which contain
1.104 - /// any data in arbitrary format. These sections can be read
1.105 - /// directly with this function. The first parameter is the type
1.106 - /// of the section, the second is a functor, which takes an \c
1.107 - /// std::istream& and an int& parameter, the latter regard to the
1.108 - /// line number of stream. The functor can read the input while
1.109 - /// the section go on, and the line number should be modified
1.110 - /// accordingly.
1.111 - template <typename Functor>
1.112 - DigraphReader& sectionStream(const std::string& type, Functor functor) {
1.113 - LEMON_ASSERT(!type.empty(), "Type is not empty.");
1.114 - LEMON_ASSERT(_sections.find(type) == _sections.end(),
1.115 - "Multiple reading of section.");
1.116 - LEMON_ASSERT(type != "nodes" && type != "arcs" && type != "edges" &&
1.117 - type != "attributes", "Multiple reading of section.");
1.118 - _sections.insert(std::make_pair(type,
1.119 - new _reader_bits::StreamSection<Functor>(functor)));
1.120 - return *this;
1.121 - }
1.122 -
1.123 - /// @}
1.124 -
1.125 /// \name Using previously constructed node or arc set
1.126 /// @{
1.127
1.128 @@ -1188,7 +1100,6 @@
1.129 bool nodes_done = _skip_nodes;
1.130 bool arcs_done = _skip_arcs;
1.131 bool attributes_done = false;
1.132 - std::set<std::string> extra_sections;
1.133
1.134 line_num = 0;
1.135 readLine();
1.136 @@ -1222,16 +1133,6 @@
1.137 attributes_done = true;
1.138 }
1.139 } else {
1.140 - if (extra_sections.find(section) != extra_sections.end()) {
1.141 - std::ostringstream msg;
1.142 - msg << "Multiple occurence of section " << section;
1.143 - throw DataFormatError(msg.str().c_str());
1.144 - }
1.145 - Sections::iterator it = _sections.find(section);
1.146 - if (it != _sections.end()) {
1.147 - extra_sections.insert(section);
1.148 - it->second->process(*_is, line_num);
1.149 - }
1.150 readLine();
1.151 skipSection();
1.152 }
1.153 @@ -1295,7 +1196,6 @@
1.154
1.155 private:
1.156
1.157 -
1.158 std::istream* _is;
1.159 bool local_is;
1.160
1.161 @@ -1322,9 +1222,6 @@
1.162 Attributes;
1.163 Attributes _attributes;
1.164
1.165 - typedef std::map<std::string, _reader_bits::Section*> Sections;
1.166 - Sections _sections;
1.167 -
1.168 bool _use_nodes;
1.169 bool _use_edges;
1.170
1.171 @@ -1386,7 +1283,6 @@
1.172 _edges_caption = other._edges_caption;
1.173 _attributes_caption = other._attributes_caption;
1.174
1.175 - _sections.swap(other._sections);
1.176 }
1.177
1.178 /// \brief Destructor
1.179 @@ -1406,11 +1302,6 @@
1.180 delete it->second;
1.181 }
1.182
1.183 - for (typename Sections::iterator it = _sections.begin();
1.184 - it != _sections.end(); ++it) {
1.185 - delete it->second;
1.186 - }
1.187 -
1.188 if (local_is) {
1.189 delete _is;
1.190 }
1.191 @@ -1603,83 +1494,6 @@
1.192
1.193 /// @}
1.194
1.195 - /// \name Section readers
1.196 - /// @{
1.197 -
1.198 - /// \brief Add a section processor with line oriented reading
1.199 - ///
1.200 - /// In the \e LGF file extra sections can be placed, which contain
1.201 - /// any data in arbitrary format. These sections can be read with
1.202 - /// this function line by line. The first parameter is the type
1.203 - /// descriptor of the section, the second is a functor, which
1.204 - /// takes just one \c std::string parameter. At the reading
1.205 - /// process, each line of the section will be given to the functor
1.206 - /// object. However, the empty lines and the comment lines are
1.207 - /// filtered out, and the leading whitespaces are stipped from
1.208 - /// each processed string.
1.209 - ///
1.210 - /// For example let's see a section, which contain several
1.211 - /// integers, which should be inserted into a vector.
1.212 - ///\code
1.213 - /// @numbers
1.214 - /// 12 45 23
1.215 - /// 4
1.216 - /// 23 6
1.217 - ///\endcode
1.218 - ///
1.219 - /// The functor is implemented as an struct:
1.220 - ///\code
1.221 - /// struct NumberSection {
1.222 - /// std::vector<int>& _data;
1.223 - /// NumberSection(std::vector<int>& data) : _data(data) {}
1.224 - /// void operator()(const std::string& line) {
1.225 - /// std::istringstream ls(line);
1.226 - /// int value;
1.227 - /// while (ls >> value) _data.push_back(value);
1.228 - /// }
1.229 - /// };
1.230 - ///
1.231 - /// // ...
1.232 - ///
1.233 - /// reader.sectionLines("numbers", NumberSection(vec));
1.234 - ///\endcode
1.235 - template <typename Functor>
1.236 - GraphReader& sectionLines(const std::string& type, Functor functor) {
1.237 - LEMON_ASSERT(!type.empty(), "Type is not empty.");
1.238 - LEMON_ASSERT(_sections.find(type) == _sections.end(),
1.239 - "Multiple reading of section.");
1.240 - LEMON_ASSERT(type != "nodes" && type != "arcs" && type != "edges" &&
1.241 - type != "attributes", "Multiple reading of section.");
1.242 - _sections.insert(std::make_pair(type,
1.243 - new _reader_bits::LineSection<Functor>(functor)));
1.244 - return *this;
1.245 - }
1.246 -
1.247 -
1.248 - /// \brief Add a section processor with stream oriented reading
1.249 - ///
1.250 - /// In the \e LGF file extra sections can be placed, which contain
1.251 - /// any data in arbitrary format. These sections can be read
1.252 - /// directly with this function. The first parameter is the type
1.253 - /// of the section, the second is a functor, which takes an \c
1.254 - /// std::istream& and an int& parameter, the latter regard to the
1.255 - /// line number of stream. The functor can read the input while
1.256 - /// the section go on, and the line number should be modified
1.257 - /// accordingly.
1.258 - template <typename Functor>
1.259 - GraphReader& sectionStream(const std::string& type, Functor functor) {
1.260 - LEMON_ASSERT(!type.empty(), "Type is not empty.");
1.261 - LEMON_ASSERT(_sections.find(type) == _sections.end(),
1.262 - "Multiple reading of section.");
1.263 - LEMON_ASSERT(type != "nodes" && type != "arcs" && type != "edges" &&
1.264 - type != "attributes", "Multiple reading of section.");
1.265 - _sections.insert(std::make_pair(type,
1.266 - new _reader_bits::StreamSection<Functor>(functor)));
1.267 - return *this;
1.268 - }
1.269 -
1.270 - /// @}
1.271 -
1.272 /// \name Using previously constructed node or edge set
1.273 /// @{
1.274
1.275 @@ -2081,7 +1895,6 @@
1.276 bool nodes_done = _skip_nodes;
1.277 bool edges_done = _skip_edges;
1.278 bool attributes_done = false;
1.279 - std::set<std::string> extra_sections;
1.280
1.281 line_num = 0;
1.282 readLine();
1.283 @@ -2115,16 +1928,6 @@
1.284 attributes_done = true;
1.285 }
1.286 } else {
1.287 - if (extra_sections.find(section) != extra_sections.end()) {
1.288 - std::ostringstream msg;
1.289 - msg << "Multiple occurence of section " << section;
1.290 - throw DataFormatError(msg.str().c_str());
1.291 - }
1.292 - Sections::iterator it = _sections.find(section);
1.293 - if (it != _sections.end()) {
1.294 - extra_sections.insert(section);
1.295 - it->second->process(*_is, line_num);
1.296 - }
1.297 readLine();
1.298 skipSection();
1.299 }
1.300 @@ -2174,6 +1977,253 @@
1.301 return tmp;
1.302 }
1.303
1.304 + /// \brief Section reader class
1.305 + ///
1.306 + /// In the \e LGF file extra sections can be placed, which contain
1.307 + /// any data in arbitrary format. Such sections can be read with
1.308 + /// this class. A reading rule can be added with two different
1.309 + /// functions, with the \c sectionLines() function a functor can
1.310 + /// process the section line-by-line. While with the \c
1.311 + /// sectionStream() member the section can be read from an input
1.312 + /// stream.
1.313 + class SectionReader {
1.314 + private:
1.315 +
1.316 + std::istream* _is;
1.317 + bool local_is;
1.318 +
1.319 + typedef std::map<std::string, _reader_bits::Section*> Sections;
1.320 + Sections _sections;
1.321 +
1.322 + int line_num;
1.323 + std::istringstream line;
1.324 +
1.325 + public:
1.326 +
1.327 + /// \brief Constructor
1.328 + ///
1.329 + /// Construct a section reader, which reads from the given input
1.330 + /// stream.
1.331 + SectionReader(std::istream& is)
1.332 + : _is(&is), local_is(false) {}
1.333 +
1.334 + /// \brief Constructor
1.335 + ///
1.336 + /// Construct a section reader, which reads from the given file.
1.337 + SectionReader(const std::string& fn)
1.338 + : _is(new std::ifstream(fn.c_str())), local_is(true) {}
1.339 +
1.340 + /// \brief Constructor
1.341 + ///
1.342 + /// Construct a section reader, which reads from the given file.
1.343 + SectionReader(const char* fn)
1.344 + : _is(new std::ifstream(fn)), local_is(true) {}
1.345 +
1.346 + /// \brief Copy constructor
1.347 + ///
1.348 + /// The copy constructor transfers all data from the other reader,
1.349 + /// therefore the copied reader will not be usable more.
1.350 + SectionReader(SectionReader& other)
1.351 + : _is(other._is), local_is(other.local_is) {
1.352 +
1.353 + other._is = 0;
1.354 + other.local_is = false;
1.355 +
1.356 + _sections.swap(other._sections);
1.357 + }
1.358 +
1.359 + /// \brief Destructor
1.360 + ~SectionReader() {
1.361 + for (Sections::iterator it = _sections.begin();
1.362 + it != _sections.end(); ++it) {
1.363 + delete it->second;
1.364 + }
1.365 +
1.366 + if (local_is) {
1.367 + delete _is;
1.368 + }
1.369 +
1.370 + }
1.371 +
1.372 + private:
1.373 +
1.374 + SectionReader& operator=(const SectionReader&);
1.375 +
1.376 + public:
1.377 +
1.378 + /// \name Section readers
1.379 + /// @{
1.380 +
1.381 + /// \brief Add a section processor with line oriented reading
1.382 + ///
1.383 + /// The first parameter is the type descriptor of the section, the
1.384 + /// second is a functor, which takes just one \c std::string
1.385 + /// parameter. At the reading process, each line of the section
1.386 + /// will be given to the functor object. However, the empty lines
1.387 + /// and the comment lines are filtered out, and the leading
1.388 + /// whitespaces are trimmed from each processed string.
1.389 + ///
1.390 + /// For example let's see a section, which contain several
1.391 + /// integers, which should be inserted into a vector.
1.392 + ///\code
1.393 + /// @numbers
1.394 + /// 12 45 23
1.395 + /// 4
1.396 + /// 23 6
1.397 + ///\endcode
1.398 + ///
1.399 + /// The functor is implemented as an struct:
1.400 + ///\code
1.401 + /// struct NumberSection {
1.402 + /// std::vector<int>& _data;
1.403 + /// NumberSection(std::vector<int>& data) : _data(data) {}
1.404 + /// void operator()(const std::string& line) {
1.405 + /// std::istringstream ls(line);
1.406 + /// int value;
1.407 + /// while (ls >> value) _data.push_back(value);
1.408 + /// }
1.409 + /// };
1.410 + ///
1.411 + /// // ...
1.412 + ///
1.413 + /// reader.sectionLines("numbers", NumberSection(vec));
1.414 + ///\endcode
1.415 + template <typename Functor>
1.416 + SectionReader& sectionLines(const std::string& type, Functor functor) {
1.417 + LEMON_ASSERT(!type.empty(), "Type is not empty.");
1.418 + LEMON_ASSERT(_sections.find(type) == _sections.end(),
1.419 + "Multiple reading of section.");
1.420 + _sections.insert(std::make_pair(type,
1.421 + new _reader_bits::LineSection<Functor>(functor)));
1.422 + return *this;
1.423 + }
1.424 +
1.425 +
1.426 + /// \brief Add a section processor with stream oriented reading
1.427 + ///
1.428 + /// The first parameter is the type of the section, the second is
1.429 + /// a functor, which takes an \c std::istream& and an int&
1.430 + /// parameter, the latter regard to the line number of stream. The
1.431 + /// functor can read the input while the section go on, and the
1.432 + /// line number should be modified accordingly.
1.433 + template <typename Functor>
1.434 + SectionReader& sectionStream(const std::string& type, Functor functor) {
1.435 + LEMON_ASSERT(!type.empty(), "Type is not empty.");
1.436 + LEMON_ASSERT(_sections.find(type) == _sections.end(),
1.437 + "Multiple reading of section.");
1.438 + _sections.insert(std::make_pair(type,
1.439 + new _reader_bits::StreamSection<Functor>(functor)));
1.440 + return *this;
1.441 + }
1.442 +
1.443 + /// @}
1.444 +
1.445 + private:
1.446 +
1.447 + bool readLine() {
1.448 + std::string str;
1.449 + while(++line_num, std::getline(*_is, str)) {
1.450 + line.clear(); line.str(str);
1.451 + char c;
1.452 + if (line >> std::ws >> c && c != '#') {
1.453 + line.putback(c);
1.454 + return true;
1.455 + }
1.456 + }
1.457 + return false;
1.458 + }
1.459 +
1.460 + bool readSuccess() {
1.461 + return static_cast<bool>(*_is);
1.462 + }
1.463 +
1.464 + void skipSection() {
1.465 + char c;
1.466 + while (readSuccess() && line >> c && c != '@') {
1.467 + readLine();
1.468 + }
1.469 + line.putback(c);
1.470 + }
1.471 +
1.472 + public:
1.473 +
1.474 +
1.475 + /// \name Execution of the reader
1.476 + /// @{
1.477 +
1.478 + /// \brief Start the batch processing
1.479 + ///
1.480 + /// This function starts the batch processing
1.481 + void run() {
1.482 +
1.483 + LEMON_ASSERT(_is != 0, "This reader assigned to an other reader");
1.484 +
1.485 + std::set<std::string> extra_sections;
1.486 +
1.487 + line_num = 0;
1.488 + readLine();
1.489 + skipSection();
1.490 +
1.491 + while (readSuccess()) {
1.492 + try {
1.493 + char c;
1.494 + std::string section, caption;
1.495 + line >> c;
1.496 + _reader_bits::readToken(line, section);
1.497 + _reader_bits::readToken(line, caption);
1.498 +
1.499 + if (line >> c)
1.500 + throw DataFormatError("Extra character on the end of line");
1.501 +
1.502 + if (extra_sections.find(section) != extra_sections.end()) {
1.503 + std::ostringstream msg;
1.504 + msg << "Multiple occurence of section " << section;
1.505 + throw DataFormatError(msg.str().c_str());
1.506 + }
1.507 + Sections::iterator it = _sections.find(section);
1.508 + if (it != _sections.end()) {
1.509 + extra_sections.insert(section);
1.510 + it->second->process(*_is, line_num);
1.511 + }
1.512 + readLine();
1.513 + skipSection();
1.514 + } catch (DataFormatError& error) {
1.515 + error.line(line_num);
1.516 + throw;
1.517 + }
1.518 + }
1.519 + for (Sections::iterator it = _sections.begin();
1.520 + it != _sections.end(); ++it) {
1.521 + if (extra_sections.find(it->first) == extra_sections.end()) {
1.522 + std::ostringstream os;
1.523 + os << "Cannot find section: " << it->first;
1.524 + throw DataFormatError(os.str().c_str());
1.525 + }
1.526 + }
1.527 + }
1.528 +
1.529 + /// @}
1.530 +
1.531 + };
1.532 +
1.533 + /// \relates SectionReader
1.534 + inline SectionReader sectionReader(std::istream& is) {
1.535 + SectionReader tmp(is);
1.536 + return tmp;
1.537 + }
1.538 +
1.539 + /// \relates SectionReader
1.540 + inline SectionReader sectionReader(const std::string& fn) {
1.541 + SectionReader tmp(fn);
1.542 + return tmp;
1.543 + }
1.544 +
1.545 + /// \relates SectionReader
1.546 + inline SectionReader sectionReader(const char* fn) {
1.547 + SectionReader tmp(fn);
1.548 + return tmp;
1.549 + }
1.550 +
1.551 /// \ingroup lemon_io
1.552 ///
1.553 /// \brief Reader for the contents of the \ref lgf-format "LGF" file