1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/src/lemon/graph_reader.h Mon Feb 07 11:29:25 2005 +0000
1.3 @@ -0,0 +1,674 @@
1.4 +/* -*- C++ -*-
1.5 + * src/lemon/graph_reader.h - Part of LEMON, a generic C++ optimization library
1.6 + *
1.7 + * Copyright (C) 2004 Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
1.8 + * (Egervary Combinatorial Optimization Research Group, EGRES).
1.9 + *
1.10 + * Permission to use, modify and distribute this software is granted
1.11 + * provided that this copyright notice appears in all copies. For
1.12 + * precise terms see the accompanying LICENSE file.
1.13 + *
1.14 + * This software is provided "AS IS" with no warranty of any kind,
1.15 + * express or implied, and with no claim as to its suitability for any
1.16 + * purpose.
1.17 + *
1.18 + */
1.19 +
1.20 +///\ingroup gio
1.21 +///\file
1.22 +///\brief Graph reader.
1.23 +
1.24 +#include <iostream>
1.25 +#include <sstream>
1.26 +
1.27 +#include <map>
1.28 +#include <vector>
1.29 +
1.30 +#include <memory>
1.31 +
1.32 +#include <lemon/error.h>
1.33 +
1.34 +/// \todo fix exceptions
1.35 +
1.36 +
1.37 +namespace lemon {
1.38 +
1.39 + // Exceptions
1.40 +
1.41 + class IOException {
1.42 + public:
1.43 + virtual ~IOException() {}
1.44 + virtual string what() const = 0;
1.45 + };
1.46 +
1.47 + class DataFormatException : public IOException {
1.48 + std::string message;
1.49 + public:
1.50 + DataFormatException(const std::string& _message)
1.51 + : message(_message) {}
1.52 + std::string what() const {
1.53 + return "DataFormatException: " + message;
1.54 + }
1.55 + };
1.56 +
1.57 + template <typename _Exception>
1.58 + class StreamException : public _Exception {
1.59 + public:
1.60 + typedef _Exception Exception;
1.61 + StreamException(int _line, Exception _exception)
1.62 + : Exception(_exception), line_num(_line) {}
1.63 + virtual int line() const {
1.64 + return line_num;
1.65 + }
1.66 +
1.67 + virtual ~StreamException() {}
1.68 +
1.69 + virtual std::string what() const {
1.70 + ostringstream os;
1.71 + os << Exception::what() << " in line " << line();
1.72 + return os.str();
1.73 + }
1.74 + private:
1.75 + int line_num;
1.76 + };
1.77 +
1.78 +
1.79 + /// \brief Standard ReaderTraits for the GraphReader class.
1.80 + ///
1.81 + /// Standard ReaderTraits for the GraphReader class.
1.82 + /// It defines standard reading method for all type of value.
1.83 + struct DefaultReaderTraits {
1.84 +
1.85 + /// \brief Template class for reading an value.
1.86 + ///
1.87 + /// Template class for reading an value.
1.88 + template <typename _Value>
1.89 + struct Reader {
1.90 + /// The value type.
1.91 + typedef _Value Value;
1.92 + /// \brief Reads a value from the given stream.
1.93 + ///
1.94 + /// Reads a value from the given stream.
1.95 + void read(std::istream& is, Value& value) {
1.96 + if (!(is >> value))
1.97 + throw DataFormatException("Default Reader format exception");
1.98 + }
1.99 + };
1.100 +
1.101 + /// The reader class for the not needed maps.
1.102 + typedef Reader<std::string> DefaultReader;
1.103 +
1.104 + };
1.105 +
1.106 + /// \brief Reader class for quoted strings.
1.107 + ///
1.108 + /// Reader class for quoted strings. It can process the escape
1.109 + /// sequences in the string.
1.110 + class QuotedStringReader {
1.111 + public:
1.112 + typedef std::string Value;
1.113 +
1.114 + /// \brief Constructor for the reader.
1.115 + ///
1.116 + /// Constructor for the reader. If the given parameter is true
1.117 + /// the reader processes the escape sequences.
1.118 + QuotedStringReader(bool _escaped = true) : escaped(_escaped) {}
1.119 +
1.120 + /// \brief Reads a quoted string from the given stream.
1.121 + ///
1.122 + /// Reads a quoted string from the given stream.
1.123 + void read(std::istream& is, std::string& value) {
1.124 + char c;
1.125 + value.clear();
1.126 + is >> ws;
1.127 + if (!is.get(c) || c != '\"')
1.128 + throw DataFormatException("Quoted string format");
1.129 + while (is.get(c) && c != '\"') {
1.130 + if (escaped && c == '\\') {
1.131 + value += readEscape(is);
1.132 + } else {
1.133 + value += c;
1.134 + }
1.135 + }
1.136 + if (!is) throw DataFormatException("Quoted string format");
1.137 + }
1.138 +
1.139 + private:
1.140 +
1.141 + static char readEscape(std::istream& is) {
1.142 + char c;
1.143 + switch (is.get(c), c) {
1.144 + case '\\':
1.145 + return '\\';
1.146 + case '\"':
1.147 + return '\"';
1.148 + case '\'':
1.149 + return '\'';
1.150 + case '\?':
1.151 + return '\?';
1.152 + case 'a':
1.153 + return '\a';
1.154 + case 'b':
1.155 + return '\b';
1.156 + case 'f':
1.157 + return '\f';
1.158 + case 'n':
1.159 + return '\n';
1.160 + case 'r':
1.161 + return '\r';
1.162 + case 't':
1.163 + return '\t';
1.164 + case 'v':
1.165 + return '\v';
1.166 + case 'x':
1.167 + {
1.168 + int code;
1.169 + if (!is.get(c) || !isHex(c))
1.170 + throw DataFormatException("Escape format exception");
1.171 + else if (code = valueHex(c), !is.get(c) || !isHex(c)) is.putback(c);
1.172 + else code = code * 16 + valueHex(c);
1.173 + return code;
1.174 + }
1.175 + default:
1.176 + {
1.177 + int code;
1.178 + if (!isOct(c))
1.179 + throw DataFormatException("Escape format exception");
1.180 + else if (code = valueOct(c), !is.get(c) || !isOct(c))
1.181 + is.putback(c);
1.182 + else if (code = code * 8 + valueOct(c), !is.get(c) || !isOct(c))
1.183 + is.putback(c);
1.184 + else code = code * 8 + valueOct(c);
1.185 + return code;
1.186 + }
1.187 + }
1.188 + }
1.189 +
1.190 + static bool isOct(char c) {
1.191 + return '0' <= c && c <='7';
1.192 + }
1.193 +
1.194 + static int valueOct(char c) {
1.195 + return c - '0';
1.196 + }
1.197 +
1.198 + static bool isHex(char c) {
1.199 + return ('0' <= c && c <= '9') ||
1.200 + ('a' <= c && c <= 'z') ||
1.201 + ('A' <= c && c <= 'Z');
1.202 + }
1.203 +
1.204 + static int valueHex(char c) {
1.205 + if ('0' <= c && c <= '9') return c - '0';
1.206 + if ('a' <= c && c <= 'z') return c - 'a' + 10;
1.207 + return c - 'A' + 10;
1.208 + }
1.209 +
1.210 + bool escaped;
1.211 + };
1.212 +
1.213 + /// \brief The graph reader class.
1.214 + ///
1.215 + /// The reader class for the graph input.
1.216 + /// \see graph-io-page
1.217 + template <typename _Graph, typename _ReaderTraits = DefaultReaderTraits>
1.218 + class GraphReader {
1.219 + public:
1.220 +
1.221 + typedef _Graph Graph;
1.222 + typedef typename Graph::Node Node;
1.223 + typedef typename Graph::Edge Edge;
1.224 +
1.225 + typedef _ReaderTraits ReaderTraits;
1.226 + typedef typename ReaderTraits::DefaultReader DefaultReader;
1.227 +
1.228 + /// \brief Construct a new GraphReader.
1.229 + ///
1.230 + /// Construct a new GraphReader. It reads from the given map,
1.231 + /// it constructs the given map and it use the given reader as the
1.232 + /// default skipper.
1.233 + GraphReader(std::istream& _is, Graph& _graph,
1.234 + const DefaultReader& _reader = DefaultReader())
1.235 + : is(_is), graph(_graph), nodeSkipper(_reader), edgeSkipper(_reader) {}
1.236 +
1.237 + /// \brief Destruct the graph reader.
1.238 + ///
1.239 + /// Destruct the graph reader.
1.240 + ~GraphReader() {
1.241 +
1.242 + for (typename NodeMapReaders::iterator it = node_map_readers.begin();
1.243 + it != node_map_readers.end(); ++it) {
1.244 + delete it->second;
1.245 + }
1.246 +
1.247 + for (typename EdgeMapReaders::iterator it = edge_map_readers.begin();
1.248 + it != edge_map_readers.end(); ++it) {
1.249 + delete it->second;
1.250 + }
1.251 +
1.252 + }
1.253 +
1.254 + /// \brief Add a new node map reader command for the reader.
1.255 + ///
1.256 + /// Add a new node map reader command for the reader.
1.257 + template <typename Map>
1.258 + GraphReader& addNodeMap(std::string name, Map& map) {
1.259 + return addNodeMap<typename ReaderTraits::template
1.260 + Reader<typename Map::Value>, Map>(name, map);
1.261 + }
1.262 +
1.263 + /// \brief Add a new node map reader command for the reader.
1.264 + ///
1.265 + /// Add a new node map reader command for the reader.
1.266 + template <typename Reader, typename Map>
1.267 + GraphReader& addNodeMap(std::string name, Map& map,
1.268 + const Reader& reader = Reader()) {
1.269 + if (node_map_readers.find(name) != node_map_readers.end()) {
1.270 + throw Exception() << "Multiple read rule for node map: " << name;
1.271 + }
1.272 + node_map_readers.insert(
1.273 + make_pair(name, new MapReader<Node, Map, Reader>(map, reader)));
1.274 + return *this;
1.275 + }
1.276 +
1.277 + /// \brief Add a new node map skipper command for the reader.
1.278 + ///
1.279 + /// Add a new node map skipper command for the reader.
1.280 + template <typename Reader>
1.281 + GraphReader& skipNodeMap(std::string name,
1.282 + const Reader& reader = Reader()) {
1.283 + if (node_map_readers.find(name) != node_map_readers.end()) {
1.284 + throw Exception() << "Multiple read rule for node map: " << name;
1.285 + }
1.286 + node_map_readers.insert(
1.287 + make_pair(name, new SkipReader<Node, Reader>(reader)));
1.288 + return *this;
1.289 + }
1.290 +
1.291 + /// \brief Add a new edge map reader command for the reader.
1.292 + ///
1.293 + /// Add a new edge map reader command for the reader.
1.294 + template <typename Map>
1.295 + GraphReader& addEdgeMap(std::string name, Map& map) {
1.296 + return addEdgeMap<typename ReaderTraits::template
1.297 + Reader<typename Map::Value>, Map>(name, map);
1.298 + }
1.299 +
1.300 +
1.301 + /// \brief Add a new edge map reader command for the reader.
1.302 + ///
1.303 + /// Add a new edge map reader command for the reader.
1.304 + template <typename Reader, typename Map>
1.305 + GraphReader& addEdgeMap(std::string name, Map& map,
1.306 + const Reader& reader = Reader()) {
1.307 + if (edge_map_readers.find(name) != edge_map_readers.end()) {
1.308 + throw Exception() << "Multiple read rule for edge map: " << name;
1.309 + }
1.310 + edge_map_readers.insert(
1.311 + make_pair(name, new MapReader<Edge, Map, Reader>(map, reader)));
1.312 + return *this;
1.313 + }
1.314 +
1.315 + /// \brief Add a new edge map skipper command for the reader.
1.316 + ///
1.317 + /// Add a new edge map skipper command for the reader.
1.318 + template <typename Reader>
1.319 + GraphReader& skipEdgeMap(std::string name,
1.320 + const Reader& reader = Reader()) {
1.321 + if (edge_map_readers.find(name) != edge_map_readers.end()) {
1.322 + throw Exception() << "Multiple read rule for edge map: " << name;
1.323 + }
1.324 + edge_map_readers.insert(
1.325 + make_pair(name, new SkipReader<Edge, Reader>(reader)));
1.326 + return *this;
1.327 + }
1.328 +
1.329 + /// \brief Add a new labeled node reader for the reader.
1.330 + ///
1.331 + /// Add a new labeled node reader for the reader.
1.332 + GraphReader& addNode(std::string name, Node& node) {
1.333 + if (node_readers.find(name) != node_readers.end()) {
1.334 + throw Exception() << "Multiple read rule for node";
1.335 + }
1.336 + node_readers.insert(make_pair(name, &node));
1.337 + return *this;
1.338 + }
1.339 +
1.340 + /// \brief Add a new labeled edge reader for the reader.
1.341 + ///
1.342 + /// Add a new labeled edge reader for the reader.
1.343 + GraphReader& addEdge(std::string name, Edge& edge) {
1.344 + if (edge_readers.find(name) != edge_readers.end()) {
1.345 + throw Exception() << "Multiple read rule for edge";
1.346 + }
1.347 + edge_readers.insert(make_pair(name, &edge));
1.348 + return *this;
1.349 + }
1.350 +
1.351 + /// \brief Executes the reader commands.
1.352 + ///
1.353 + /// Executes the reader commands.
1.354 + void run() {
1.355 + int line_num = 0;
1.356 + std::auto_ptr<InverterBase<Node> > nodeInverter;
1.357 + std::auto_ptr<InverterBase<Edge> > edgeInverter;
1.358 + try {
1.359 + std::string line = readNotEmptyLine(is, line_num);
1.360 + if (line.find("@nodeset") == 0) {
1.361 + line = readNodeSet(line_num, nodeInverter);
1.362 + }
1.363 + if (line.find("@edgeset") == 0) {
1.364 + line = readEdgeSet(line_num, edgeInverter, nodeInverter);
1.365 + }
1.366 + if (line.find("@nodes") == 0) {
1.367 + line = readNodes(line_num, nodeInverter);
1.368 + }
1.369 + if (line.find("@edges") == 0) {
1.370 + line = readEdges(line_num, edgeInverter);
1.371 + }
1.372 + if (line.find("@end") != 0) {
1.373 + throw DataFormatException("Invalid control sequence: " + line);
1.374 + }
1.375 + } catch (DataFormatException e) {
1.376 + throw StreamException<DataFormatException>(line_num, e);
1.377 + }
1.378 + }
1.379 +
1.380 + private:
1.381 +
1.382 + template <typename Item> class InverterBase;
1.383 +
1.384 + std::string readNodeSet(int& line_num,
1.385 + auto_ptr<InverterBase<Node> > & nodeInverter) {
1.386 + std::vector<ReaderBase<Node>* > index;
1.387 + {
1.388 + std::string line = readNotEmptyLine(is, line_num);
1.389 + std::string id;
1.390 + std::istringstream ls(line);
1.391 + while (ls >> id) {
1.392 + if (id[0] == '#') break;
1.393 + typename NodeMapReaders::iterator it = node_map_readers.find(id);
1.394 + if (it != node_map_readers.end()) {
1.395 + index.push_back(it->second);
1.396 + node_map_readers.erase(it);
1.397 + } else {
1.398 + index.push_back(&nodeSkipper);
1.399 + }
1.400 + }
1.401 + }
1.402 +
1.403 + if (index.size() == 0) {
1.404 + throw DataFormatException("No node map found");
1.405 + }
1.406 +
1.407 + nodeInverter = auto_ptr<InverterBase<Node> >(index[0]->getInverter());
1.408 + std::string line;
1.409 + while (line = readNotEmptyLine(is, line_num), line[0] != '@') {
1.410 + Node node = graph.addNode();
1.411 + std::istringstream ls(line);
1.412 + nodeInverter->read(ls, node);
1.413 + for (int i = 1; i < (int)index.size(); ++i) {
1.414 + index[i]->read(ls, node);
1.415 + }
1.416 + }
1.417 + return line;
1.418 + }
1.419 +
1.420 + std::string readEdgeSet(int& line_num,
1.421 + auto_ptr<InverterBase<Edge> > & edgeInverter,
1.422 + auto_ptr<InverterBase<Node> > & nodeInverter) {
1.423 + std::vector<ReaderBase<Edge>*> index;
1.424 + {
1.425 + std::string line = readNotEmptyLine(is, line_num);
1.426 + std::string id;
1.427 + std::istringstream ls(line);
1.428 + while (ls >> id) {
1.429 + if (id[0] == '#') break;
1.430 + typename EdgeMapReaders::iterator it = edge_map_readers.find(id);
1.431 + if (it != edge_map_readers.end()) {
1.432 + index.push_back(it->second);
1.433 + edge_map_readers.erase(it);
1.434 + } else {
1.435 + index.push_back(&edgeSkipper);
1.436 + }
1.437 + }
1.438 + }
1.439 +
1.440 + if (index.size() == 0) {
1.441 + throw DataFormatException("No edge map found");
1.442 + }
1.443 +
1.444 + edgeInverter = auto_ptr<InverterBase<Edge> >(index[0]->getInverter());
1.445 + std::string line;
1.446 + while (line = readNotEmptyLine(is, line_num), line[0] != '@') {
1.447 + std::istringstream ls(line);
1.448 + Node source = nodeInverter->read(ls);
1.449 + Node target = nodeInverter->read(ls);
1.450 + Edge edge = graph.addEdge(source, target);
1.451 + edgeInverter->read(ls, edge);
1.452 + for (int i = 1; i < (int)index.size(); ++i) {
1.453 + index[i]->read(ls, edge);
1.454 + }
1.455 + }
1.456 + return line;
1.457 + }
1.458 +
1.459 + std::string readNodes(int& line_num,
1.460 + auto_ptr<InverterBase<Node> >& nodeInverter) {
1.461 + std::string line;
1.462 + while (line = readNotEmptyLine(is, line_num), line[0] != '@') {
1.463 + std::istringstream ls(line);
1.464 + std::string name;
1.465 + ls >> name;
1.466 + typename NodeReaders::iterator it = node_readers.find(name);
1.467 + if (it != node_readers.end()) {
1.468 + *(it -> second) = nodeInverter->read(ls);
1.469 + }
1.470 + }
1.471 + return line;
1.472 + }
1.473 +
1.474 + std::string readEdges(int& line_num,
1.475 + auto_ptr<InverterBase<Edge> >& edgeInverter) {
1.476 + std::string line;
1.477 + while (line = readNotEmptyLine(is, line_num), line[0] != '@') {
1.478 + std::istringstream ls(line);
1.479 + std::string name;
1.480 + ls >> name;
1.481 + typename EdgeReaders::iterator it = edge_readers.find(name);
1.482 + if (it != edge_readers.end()) {
1.483 + *(it -> second) = edgeInverter->read(ls);
1.484 + }
1.485 + }
1.486 + return line;
1.487 + }
1.488 +
1.489 + std::string readNotEmptyLine(std::istream& is, int& line_num) {
1.490 + std::string line;
1.491 + while (++line_num, getline(is, line)) {
1.492 + int vi = line.find_first_not_of(" \t");
1.493 + if (vi != (int)string::npos && line[vi] != '#') {
1.494 + return line.substr(vi);
1.495 + }
1.496 + }
1.497 + throw DataFormatException("End of stream");
1.498 + }
1.499 +
1.500 + // Inverters store and give back the Item from the id,
1.501 + // and may put the ids into a map.
1.502 +
1.503 + template <typename _Item>
1.504 + class InverterBase {
1.505 + public:
1.506 + typedef _Item Item;
1.507 + virtual void read(std::istream&, const Item&) = 0;
1.508 + virtual Item read(std::istream&) = 0;
1.509 + };
1.510 +
1.511 + template <typename _Item, typename _Map, typename _Reader>
1.512 + class MapReaderInverter : public InverterBase<_Item> {
1.513 + public:
1.514 + typedef _Item Item;
1.515 + typedef _Reader Reader;
1.516 + typedef typename Reader::Value Value;
1.517 + typedef _Map Map;
1.518 + typedef std::map<Value, Item> Inverse;
1.519 +
1.520 + Map& map;
1.521 + Reader reader;
1.522 + Inverse inverse;
1.523 +
1.524 + MapReaderInverter(Map& _map, const Reader& _reader)
1.525 + : map(_map), reader(_reader) {}
1.526 +
1.527 + virtual ~MapReaderInverter() {}
1.528 +
1.529 + virtual void read(std::istream& is, const Item& item) {
1.530 + Value value;
1.531 + reader.read(is, value);
1.532 + map.set(item, value);
1.533 + typename Inverse::iterator it = inverse.find(value);
1.534 + if (it == inverse.end()) {
1.535 + inverse.insert(make_pair(value, item));
1.536 + } else {
1.537 + throw DataFormatException("Multiple ID occurence");
1.538 + }
1.539 + }
1.540 +
1.541 + virtual Item read(std::istream& is) {
1.542 + Value value;
1.543 + reader.read(is, value);
1.544 + typename Inverse::const_iterator it = inverse.find(value);
1.545 + if (it != inverse.end()) {
1.546 + return it->second;
1.547 + } else {
1.548 + throw DataFormatException("Invalid ID");
1.549 + }
1.550 + }
1.551 + };
1.552 +
1.553 + template <typename _Item, typename _Reader>
1.554 + class SkipReaderInverter : public InverterBase<_Item> {
1.555 + public:
1.556 + typedef _Item Item;
1.557 + typedef _Reader Reader;
1.558 + typedef typename Reader::Value Value;
1.559 + typedef std::map<Value, Item> Inverse;
1.560 +
1.561 + Reader reader;
1.562 +
1.563 + SkipReaderInverter(const Reader& _reader)
1.564 + : reader(_reader) {}
1.565 +
1.566 + virtual ~SkipReaderInverter() {}
1.567 +
1.568 + virtual void read(std::istream& is, const Item& item) {
1.569 + Value value;
1.570 + reader.read(is, value);
1.571 + typename Inverse::iterator it = inverse.find(value);
1.572 + if (it == inverse.end()) {
1.573 + inverse.insert(make_pair(value, item));
1.574 + } else {
1.575 + throw DataFormatException("Multiple ID occurence");
1.576 + }
1.577 + }
1.578 +
1.579 + virtual Item read(std::istream& is) {
1.580 + Value value;
1.581 + reader.read(is, value);
1.582 + typename Inverse::const_iterator it = inverse.find(value);
1.583 + if (it != inverse.end()) {
1.584 + return it->second;
1.585 + } else {
1.586 + throw DataFormatException("Invalid ID");
1.587 + }
1.588 + }
1.589 + private:
1.590 + Inverse inverse;
1.591 + };
1.592 +
1.593 + // Readers
1.594 +
1.595 + template <typename _Item>
1.596 + class ReaderBase {
1.597 + public:
1.598 + typedef _Item Item;
1.599 +
1.600 + // virtual ~ReaderBase() {}
1.601 +
1.602 + virtual void read(std::istream& is, const Item& item) = 0;
1.603 + virtual InverterBase<_Item>* getInverter() = 0;
1.604 + };
1.605 +
1.606 + template <typename _Item, typename _Map, typename _Reader>
1.607 + class MapReader : public ReaderBase<_Item> {
1.608 + public:
1.609 + typedef _Map Map;
1.610 + typedef _Reader Reader;
1.611 + typedef typename Reader::Value Value;
1.612 + typedef _Item Item;
1.613 +
1.614 + Map& map;
1.615 + Reader reader;
1.616 +
1.617 + MapReader(Map& _map, const Reader& _reader)
1.618 + : map(_map), reader(_reader) {}
1.619 +
1.620 + virtual ~MapReader() {}
1.621 +
1.622 + virtual void read(std::istream& is, const Item& item) {
1.623 + Value value;
1.624 + reader.read(is, value);
1.625 + map.set(item, value);
1.626 + }
1.627 +
1.628 + virtual InverterBase<_Item>* getInverter() {
1.629 + return new MapReaderInverter<Item, Map, Reader>(map, reader);
1.630 + }
1.631 + };
1.632 +
1.633 +
1.634 + template <typename _Item, typename _Reader>
1.635 + class SkipReader : public ReaderBase<_Item> {
1.636 + public:
1.637 + typedef _Reader Reader;
1.638 + typedef typename Reader::Value Value;
1.639 + typedef _Item Item;
1.640 +
1.641 + Reader reader;
1.642 + SkipReader(const Reader& _reader) : reader(_reader) {}
1.643 +
1.644 + virtual ~SkipReader() {}
1.645 +
1.646 + virtual void read(std::istream& is, const Item& item) {
1.647 + Value value;
1.648 + reader.read(is, value);
1.649 + }
1.650 +
1.651 + virtual InverterBase<Item>* getInverter() {
1.652 + return new SkipReaderInverter<Item, Reader>(reader);
1.653 + }
1.654 + };
1.655 +
1.656 +
1.657 + typedef std::map<std::string, ReaderBase<Node>*> NodeMapReaders;
1.658 + NodeMapReaders node_map_readers;
1.659 +
1.660 + typedef std::map<std::string, ReaderBase<Edge>*> EdgeMapReaders;
1.661 + EdgeMapReaders edge_map_readers;
1.662 +
1.663 + typedef std::map<std::string, Node*> NodeReaders;
1.664 + NodeReaders node_readers;
1.665 +
1.666 + typedef std::map<std::string, Edge*> EdgeReaders;
1.667 + EdgeReaders edge_readers;
1.668 +
1.669 + std::istream& is;
1.670 + Graph& graph;
1.671 +
1.672 + SkipReader<Node, DefaultReader> nodeSkipper;
1.673 + SkipReader<Edge, DefaultReader> edgeSkipper;
1.674 +
1.675 + };
1.676 +
1.677 +}