deba@1032: /* -*- C++ -*- deba@1032: * src/lemon/graph_reader.h - Part of LEMON, a generic C++ optimization library deba@1032: * deba@1032: * Copyright (C) 2004 Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport deba@1032: * (Egervary Combinatorial Optimization Research Group, EGRES). deba@1032: * deba@1032: * Permission to use, modify and distribute this software is granted deba@1032: * provided that this copyright notice appears in all copies. For deba@1032: * precise terms see the accompanying LICENSE file. deba@1032: * deba@1032: * This software is provided "AS IS" with no warranty of any kind, deba@1032: * express or implied, and with no claim as to its suitability for any deba@1032: * purpose. deba@1032: * deba@1032: */ deba@1032: deba@1032: ///\ingroup gio deba@1032: ///\file deba@1036: ///\brief Graph reader. deba@1032: deba@1032: #include deba@1032: #include deba@1032: deba@1032: #include deba@1032: #include deba@1032: deba@1037: #include deba@1037: deba@1032: #include deba@1032: deba@1032: /// \todo fix exceptions deba@1032: deba@1032: deba@1032: namespace lemon { deba@1036: deba@1036: // Exceptions deba@1036: deba@1036: class IOException { deba@1036: public: deba@1036: virtual string what() const = 0; deba@1036: }; deba@1036: deba@1036: class DataFormatException : public IOException { deba@1036: std::string message; deba@1036: public: deba@1036: DataFormatException(const std::string& _message) deba@1036: : message(_message) {} deba@1036: std::string what() const { deba@1036: return "DataFormatException: " + message; deba@1036: } deba@1036: }; deba@1036: deba@1037: template deba@1037: class StreamException : public _Exception { deba@1036: public: deba@1037: typedef _Exception Exception; deba@1037: StreamException(int _line, Exception _exception) deba@1037: : line_num(_line), Exception(_exception) {} deba@1037: virtual int line() const { deba@1037: return line_num; deba@1037: } deba@1037: virtual std::string what() const { deba@1037: ostringstream os; deba@1037: os << Exception::what() << " in line " << line(); deba@1037: return os.str(); deba@1037: } deba@1036: private: deba@1036: int line_num; deba@1036: }; deba@1036: deba@1036: deba@1036: // Readers and ReaderTraits deba@1032: deba@1032: struct DefaultReaderTraits { deba@1032: deba@1032: template deba@1032: struct Reader { deba@1032: typedef _Value Value; deba@1032: void read(std::istream& is, Value& value) { deba@1036: if (!(is >> value)) deba@1036: throw DataFormatException("Default Reader format exception"); deba@1032: } deba@1032: }; deba@1032: deba@1036: typedef Reader DefaultReader; deba@1032: deba@1032: }; deba@1032: deba@1036: class QuotedStringReader { deba@1036: public: deba@1036: typedef std::string Value; deba@1036: deba@1036: QuotedStringReader(bool _escaped = true) : escaped(_escaped) {} deba@1036: deba@1036: void read(std::istream& is, std::string& value) { deba@1036: char c; deba@1036: value.clear(); deba@1036: is >> ws; deba@1037: if (!is.get(c) || c != '\"') throw DataFormatException("Quoted string format"); deba@1036: while (is.get(c) && c != '\"') { deba@1036: if (escaped && c == '\\') { deba@1036: value += readEscape(is); deba@1036: } else { deba@1036: value += c; deba@1036: } deba@1036: } deba@1037: if (!is) throw DataFormatException("Quoted string format"); deba@1036: } deba@1036: deba@1036: private: deba@1036: deba@1036: static char readEscape(std::istream& is) { deba@1036: char c; deba@1036: switch (is.get(c), c) { deba@1036: case '\\': deba@1036: return '\\'; deba@1036: case '\"': deba@1036: return '\"'; deba@1036: case '\'': deba@1036: return '\''; deba@1036: case '\?': deba@1036: return '\?'; deba@1036: case 'a': deba@1036: return '\a'; deba@1036: case 'b': deba@1036: return '\b'; deba@1036: case 'f': deba@1036: return '\f'; deba@1036: case 'n': deba@1036: return '\n'; deba@1036: case 'r': deba@1036: return '\r'; deba@1036: case 't': deba@1036: return '\t'; deba@1036: case 'v': deba@1036: return '\v'; deba@1036: case 'x': deba@1036: { deba@1036: int code; deba@1036: if (!is.get(c) || !isHex(c)) throw DataFormatException("Escape format exception"); deba@1036: else if (code = valueHex(c), !is.get(c) || !isHex(c)) is.putback(c); deba@1036: else code = code * 16 + valueHex(c); deba@1036: return code; deba@1036: } deba@1036: default: deba@1036: { deba@1036: int code; deba@1036: if (!isOct(c)) throw DataFormatException("Escape format exception"); deba@1036: else if (code = valueOct(c), !is.get(c) || !isOct(c)) is.putback(c); deba@1036: else if (code = code * 8 + valueOct(c), !is.get(c) || !isOct(c)) is.putback(c); deba@1036: else code = code * 8 + valueOct(c); deba@1036: return code; deba@1036: } deba@1036: } deba@1036: } deba@1036: deba@1036: static bool isOct(char c) { deba@1036: return '0' <= c && c <='7'; deba@1036: } deba@1036: deba@1036: static int valueOct(char c) { deba@1036: return c - '0'; deba@1036: } deba@1036: deba@1036: static bool isHex(char c) { deba@1036: return ('0' <= c && c <= '9') || ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z'); deba@1036: } deba@1036: deba@1036: static int valueHex(char c) { deba@1036: if ('0' <= c && c <= '9') return c - '0'; deba@1036: if ('a' <= c && c <= 'z') return c - 'a' + 10; deba@1036: return c - 'A' + 10; deba@1036: } deba@1036: deba@1036: bool escaped; deba@1032: }; deba@1032: deba@1032: deba@1036: deba@1036: deba@1036: deba@1036: // Graph reader deba@1032: deba@1032: template deba@1032: class GraphReader { deba@1032: public: deba@1032: deba@1032: typedef _Graph Graph; deba@1032: typedef typename Graph::Node Node; deba@1032: typedef typename Graph::Edge Edge; deba@1032: deba@1032: typedef _ReaderTraits ReaderTraits; deba@1036: typedef typename ReaderTraits::DefaultReader DefaultReader; deba@1032: deba@1037: GraphReader(std::istream& _is, Graph& _graph, const DefaultReader& _reader = DefaultReader()) deba@1036: : is(_is), graph(_graph), nodeSkipper(_reader), edgeSkipper(_reader) {} deba@1036: deba@1036: deba@1036: ~GraphReader() { deba@1036: deba@1037: for (typename NodeMapReaders::iterator it = node_map_readers.begin(); it != node_map_readers.end(); ++it) { deba@1036: delete it->second; deba@1036: } deba@1036: deba@1037: for (typename EdgeMapReaders::iterator it = edge_map_readers.begin(); it != edge_map_readers.end(); ++it) { deba@1036: delete it->second; deba@1036: } deba@1036: deba@1036: } deba@1032: deba@1037: // Node map rules deba@1037: deba@1032: template deba@1036: GraphReader& readNodeMap(std::string name, Map& map) { deba@1036: return readNodeMap, Map>(name, map); deba@1032: } deba@1032: deba@1036: template deba@1032: GraphReader& readNodeMap(std::string name, Map& map, const Reader& reader = Reader()) { deba@1037: if (node_map_readers.find(name) != node_map_readers.end()) { deba@1037: throw Exception() << "Multiple read rule for node map: " << name; deba@1036: } deba@1037: node_map_readers.insert(make_pair(name, new MapReader(map, reader))); deba@1032: return *this; deba@1032: } deba@1032: deba@1036: template deba@1036: GraphReader& skipNodeMap(std::string name, const Reader& reader = Reader()) { deba@1037: if (node_map_readers.find(name) != node_map_readers.end()) { deba@1037: throw Exception() << "Multiple read rule for node map: " << name; deba@1036: } deba@1037: node_map_readers.insert(make_pair(name, new SkipReader(reader))); deba@1036: return *this; deba@1032: } deba@1032: deba@1037: // Edge map rules deba@1037: deba@1036: template deba@1036: GraphReader& readEdgeMap(std::string name, Map& map) { deba@1036: return readEdgeMap, Map>(name, map); deba@1036: } deba@1036: deba@1036: deba@1036: template deba@1032: GraphReader& readEdgeMap(std::string name, Map& map, const Reader& reader = Reader()) { deba@1037: if (edge_map_readers.find(name) != edge_map_readers.end()) { deba@1037: throw Exception() << "Multiple read rule for edge map: " << name; deba@1036: } deba@1037: edge_map_readers.insert(make_pair(name, new MapReader(map, reader))); deba@1032: return *this; deba@1032: } deba@1032: deba@1036: template deba@1036: GraphReader& skipEdgeMap(std::string name, const Reader& reader = Reader()) { deba@1037: if (edge_map_readers.find(name) != edge_map_readers.end()) { deba@1037: throw Exception() << "Multiple read rule for edge map: " << name; deba@1037: } deba@1037: edge_map_readers.insert(make_pair(name, new SkipReader(reader))); deba@1037: return *this; deba@1037: } deba@1037: deba@1037: // Node rules deba@1037: GraphReader& readNode(std::string name, Node& node) { deba@1037: if (node_readers.find(name) != node_readers.end()) { deba@1037: throw Exception() << "Multiple read rule for node"; deba@1037: } deba@1037: node_readers.insert(make_pair(name, &node)); deba@1037: } deba@1037: deba@1037: // Edge rules deba@1037: deba@1037: GraphReader& readEdge(std::string name, Edge& edge) { deba@1036: if (edge_readers.find(name) != edge_readers.end()) { deba@1037: throw Exception() << "Multiple read rule for edge"; deba@1036: } deba@1037: edge_readers.insert(make_pair(name, &edge)); deba@1036: } deba@1036: deba@1032: void read() { deba@1032: int line_num = 0; deba@1037: std::auto_ptr > nodeInverter; deba@1037: std::auto_ptr > edgeInverter; deba@1037: try { deba@1037: std::string line = readNotEmptyLine(is, line_num); deba@1037: if (line.find("@nodeset") == 0) { deba@1037: line = readNodeSet(line_num, nodeInverter); deba@1037: } deba@1037: if (line.find("@edgeset") == 0) { deba@1037: line = readEdgeSet(line_num, edgeInverter, nodeInverter); deba@1036: } deba@1037: if (line.find("@nodes") == 0) { deba@1037: line = readNodes(line_num, nodeInverter); deba@1037: } deba@1037: if (line.find("@edges") == 0) { deba@1037: line = readEdges(line_num, edgeInverter); deba@1037: } deba@1037: if (line.find("@end") != 0) { deba@1037: throw DataFormatException("Invalid control sequence: " + line); deba@1037: } deba@1037: } catch (DataFormatException e) { deba@1037: throw StreamException(line_num, e); deba@1037: } deba@1032: } deba@1032: deba@1032: private: deba@1032: deba@1036: template class InverterBase; deba@1036: deba@1037: std::string readNodeSet(int& line_num, auto_ptr > & nodeInverter) { deba@1037: std::vector* > index; deba@1032: { deba@1032: std::string line = readNotEmptyLine(is, line_num); deba@1032: std::string id; deba@1032: std::istringstream ls(line); deba@1032: while (ls >> id) { deba@1036: if (id[0] == '#') break; deba@1037: typename NodeMapReaders::iterator it = node_map_readers.find(id); deba@1037: if (it != node_map_readers.end()) { deba@1032: index.push_back(it->second); deba@1037: node_map_readers.erase(it); deba@1032: } else { deba@1036: index.push_back(&nodeSkipper); deba@1032: } deba@1032: } deba@1032: } deba@1036: deba@1037: if (index.size() == 0) { deba@1037: throw DataFormatException("No node map found"); deba@1037: } deba@1037: deba@1037: nodeInverter = auto_ptr >(index[0]->getInverter()); deba@1032: std::string line; deba@1032: while (line = readNotEmptyLine(is, line_num), line[0] != '@') { deba@1032: Node node = graph.addNode(); deba@1032: std::istringstream ls(line); deba@1036: nodeInverter->read(ls, node); deba@1037: for (int i = 1; i < index.size(); ++i) { deba@1036: index[i]->read(ls, node); deba@1032: } deba@1032: } deba@1037: return line; deba@1032: } deba@1032: deba@1037: std::string readEdgeSet(int& line_num, deba@1037: auto_ptr > & edgeInverter, auto_ptr > & nodeInverter) { deba@1036: std::vector*> index; deba@1036: { deba@1036: std::string line = readNotEmptyLine(is, line_num); deba@1036: std::string id; deba@1036: std::istringstream ls(line); deba@1036: while (ls >> id) { deba@1036: if (id[0] == '#') break; deba@1037: typename EdgeMapReaders::iterator it = edge_map_readers.find(id); deba@1037: if (it != edge_map_readers.end()) { deba@1036: index.push_back(it->second); deba@1037: edge_map_readers.erase(it); deba@1036: } else { deba@1036: index.push_back(&edgeSkipper); deba@1036: } deba@1036: } deba@1036: } deba@1037: deba@1037: if (index.size() == 0) { deba@1037: throw DataFormatException("No edge map found"); deba@1037: } deba@1037: deba@1037: edgeInverter = auto_ptr >(index[0]->getInverter()); deba@1036: std::string line; deba@1036: while (line = readNotEmptyLine(is, line_num), line[0] != '@') { deba@1036: std::istringstream ls(line); deba@1036: Node source = nodeInverter->read(ls); deba@1036: Node target = nodeInverter->read(ls); deba@1036: Edge edge = graph.addEdge(source, target); deba@1036: edgeInverter->read(ls, edge); deba@1037: for (int i = 1; i < index.size(); ++i) { deba@1036: index[i]->read(ls, edge); deba@1036: } deba@1036: } deba@1037: return line; deba@1037: } deba@1037: deba@1037: std::string readNodes(int& line_num, auto_ptr >& nodeInverter) { deba@1037: std::string line; deba@1037: while (line = readNotEmptyLine(is, line_num), line[0] != '@') { deba@1037: std::istringstream ls(line); deba@1037: std::string name; deba@1037: ls >> name; deba@1037: typename NodeReaders::iterator it = node_readers.find(name); deba@1037: if (it != node_readers.end()) { deba@1037: *(it -> second) = nodeInverter->read(ls); deba@1037: } deba@1037: } deba@1037: return line; deba@1037: } deba@1037: deba@1037: std::string readEdges(int& line_num, auto_ptr >& edgeInverter) { deba@1037: std::string line; deba@1037: while (line = readNotEmptyLine(is, line_num), line[0] != '@') { deba@1037: std::istringstream ls(line); deba@1037: std::string name; deba@1037: ls >> name; deba@1037: typename EdgeReaders::iterator it = edge_readers.find(name); deba@1037: if (it != edge_readers.end()) { deba@1037: *(it -> second) = edgeInverter->read(ls); deba@1037: } deba@1037: } deba@1037: return line; deba@1032: } deba@1032: deba@1032: std::string readNotEmptyLine(std::istream& is, int& line_num) { deba@1032: std::string line; deba@1032: while (++line_num, getline(is, line)) { deba@1032: int vi = line.find_first_not_of(" \t"); deba@1032: if (vi != string::npos && line[vi] != '#') { deba@1032: return line.substr(vi); deba@1032: } deba@1032: } deba@1037: throw DataFormatException("End of stream"); deba@1032: } deba@1032: deba@1037: // Inverters store and give back the Item from the id, deba@1037: // and may put the ids into a map. deba@1037: deba@1036: template deba@1036: class InverterBase { deba@1036: public: deba@1036: typedef _Item Item; deba@1037: virtual void read(std::istream&, const Item&) = 0; deba@1037: virtual Item read(std::istream&) = 0; deba@1036: }; deba@1032: deba@1036: template deba@1036: class MapReaderInverter : public InverterBase<_Item> { deba@1036: public: deba@1036: typedef _Item Item; deba@1036: typedef _Reader Reader; deba@1036: typedef typename Reader::Value Value; deba@1036: typedef _Map Map; deba@1036: typedef std::map Inverse; deba@1036: deba@1036: Map& map; deba@1036: Reader reader; deba@1036: Inverse inverse; deba@1036: deba@1036: MapReaderInverter(Map& _map, const Reader& _reader) deba@1036: : map(_map), reader(_reader) {} deba@1036: deba@1037: virtual void read(std::istream& is, const Item& item) { deba@1036: Value value; deba@1036: reader.read(is, value); deba@1036: map.set(item, value); deba@1036: typename Inverse::iterator it = inverse.find(value); deba@1036: if (it == inverse.end()) { deba@1036: inverse.insert(make_pair(value, item)); deba@1036: } else { deba@1036: throw DataFormatException("Multiple ID occurence"); deba@1036: } deba@1036: } deba@1036: deba@1037: virtual Item read(std::istream& is) { deba@1036: Value value; deba@1036: reader.read(is, value); deba@1036: typename Inverse::const_iterator it = inverse.find(value); deba@1036: if (it != inverse.end()) { deba@1036: return it->second; deba@1036: } else { deba@1036: throw DataFormatException("Invalid ID"); deba@1036: } deba@1036: } deba@1036: }; deba@1036: deba@1036: template deba@1036: class SkipReaderInverter : public InverterBase<_Item> { deba@1036: public: deba@1036: typedef _Item Item; deba@1036: typedef _Reader Reader; deba@1036: typedef typename Reader::Value Value; deba@1036: typedef std::map Inverse; deba@1036: deba@1036: Reader reader; deba@1036: deba@1036: SkipReaderInverter(const Reader& _reader) deba@1036: : reader(_reader) {} deba@1036: deba@1037: virtual void read(std::istream& is, const Item& item) { deba@1036: Value value; deba@1036: reader.read(is, value); deba@1036: typename Inverse::iterator it = inverse.find(value); deba@1036: if (it == inverse.end()) { deba@1036: inverse.insert(make_pair(value, item)); deba@1036: } else { deba@1036: throw DataFormatException("Multiple ID occurence"); deba@1036: } deba@1036: } deba@1036: deba@1037: virtual Item read(std::istream& is) { deba@1036: Value value; deba@1036: reader.read(is, value); deba@1036: typename Inverse::const_iterator it = inverse.find(value); deba@1036: if (it != inverse.end()) { deba@1036: return it->second; deba@1036: } else { deba@1036: throw DataFormatException("Invalid ID"); deba@1036: } deba@1036: } deba@1036: private: deba@1036: Inverse inverse; deba@1036: }; deba@1036: deba@1037: // Readers deba@1032: deba@1032: template deba@1036: class ReaderBase { deba@1032: public: deba@1032: typedef _Item Item; deba@1037: deba@1037: virtual void read(std::istream& is, const Item& item) = 0; deba@1036: virtual InverterBase<_Item>* getInverter() = 0; deba@1032: }; deba@1036: deba@1032: template deba@1036: class MapReader : public ReaderBase<_Item> { deba@1032: public: deba@1032: typedef _Map Map; deba@1032: typedef _Reader Reader; deba@1036: typedef typename Reader::Value Value; deba@1032: typedef _Item Item; deba@1032: deba@1032: Map& map; deba@1032: Reader reader; deba@1032: deba@1032: MapReader(Map& _map, const Reader& _reader) deba@1032: : map(_map), reader(_reader) {} deba@1032: deba@1032: deba@1037: virtual void read(std::istream& is, const Item& item) { deba@1036: Value value; deba@1032: reader.read(is, value); deba@1032: map.set(item, value); deba@1032: } deba@1036: deba@1036: virtual InverterBase<_Item>* getInverter() { deba@1036: return new MapReaderInverter(map, reader); deba@1036: } deba@1032: }; deba@1032: deba@1036: deba@1036: template deba@1036: class SkipReader : public ReaderBase<_Item> { deba@1036: public: deba@1036: typedef _Reader Reader; deba@1036: typedef typename Reader::Value Value; deba@1036: typedef _Item Item; deba@1036: deba@1036: Reader reader; deba@1036: SkipReader(const Reader& _reader) : reader(_reader) {} deba@1036: deba@1037: virtual void read(std::istream& is, const Item& item) { deba@1036: Value value; deba@1036: reader.read(is, value); deba@1036: } deba@1036: deba@1036: virtual InverterBase* getInverter() { deba@1036: return new SkipReaderInverter(reader); deba@1036: } deba@1036: }; deba@1036: deba@1036: deba@1037: typedef std::map*> NodeMapReaders; deba@1037: NodeMapReaders node_map_readers; deba@1037: deba@1037: typedef std::map*> EdgeMapReaders; deba@1037: EdgeMapReaders edge_map_readers; deba@1037: deba@1037: typedef std::map NodeReaders; deba@1032: NodeReaders node_readers; deba@1032: deba@1037: typedef std::map EdgeReaders; deba@1032: EdgeReaders edge_readers; deba@1032: deba@1036: std::istream& is; deba@1036: Graph& graph; deba@1036: deba@1036: SkipReader nodeSkipper; deba@1036: SkipReader edgeSkipper; deba@1036: deba@1032: }; deba@1032: deba@1032: }