/* -*- C++ -*- * src/lemon/graph_reader.h - Part of LEMON, a generic C++ optimization library * * Copyright (C) 2005 Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport * (Egervary Combinatorial Optimization Research Group, EGRES). * * Permission to use, modify and distribute this software is granted * provided that this copyright notice appears in all copies. For * precise terms see the accompanying LICENSE file. * * This software is provided "AS IS" with no warranty of any kind, * express or implied, and with no claim as to its suitability for any * purpose. * */ ///\ingroup gio ///\file ///\brief Graph reader. #ifndef LEMON_GRAPH_READER_H #define LEMON_GRAPH_READER_H #include #include #include #include #include #include namespace lemon { /// \brief Standard ReaderTraits for the GraphReader class. /// /// Standard ReaderTraits for the GraphReader class. /// It defines standard reading method for all type of value. struct DefaultReaderTraits { /// \brief Template class for reading an value. /// /// Template class for reading an value. template struct Reader { /// The value type. typedef _Value Value; /// \brief Reads a value from the given stream. /// /// Reads a value from the given stream. void read(std::istream& is, Value& value) { if (!(is >> value)) throw DataFormatError("Default reader format exception"); } }; /// The reader class for the not needed maps. typedef Reader DefaultReader; }; /// \brief Reader class for quoted strings. /// /// Reader class for quoted strings. It can process the escape /// sequences in the string. class QuotedStringReader { public: typedef std::string Value; /// \brief Constructor for the reader. /// /// Constructor for the reader. If the given parameter is true /// the reader processes the escape sequences. QuotedStringReader(bool _escaped = true) : escaped(_escaped) {} /// \brief Reads a quoted string from the given stream. /// /// Reads a quoted string from the given stream. void read(std::istream& is, std::string& value) { char c; value.clear(); is >> ws; if (!is.get(c) || c != '\"') throw DataFormatError("Quoted string format error"); while (is.get(c) && c != '\"') { if (escaped && c == '\\') { value += readEscape(is); } else { value += c; } } if (!is) throw DataFormatError("Quoted string format error"); } private: static char readEscape(std::istream& is) { char c; switch (is.get(c), c) { case '\\': return '\\'; case '\"': return '\"'; case '\'': return '\''; case '\?': return '\?'; case 'a': return '\a'; case 'b': return '\b'; case 'f': return '\f'; case 'n': return '\n'; case 'r': return '\r'; case 't': return '\t'; case 'v': return '\v'; case 'x': { int code; if (!is.get(c) || !isHex(c)) throw DataFormatError("Escape format error"); else if (code = valueHex(c), !is.get(c) || !isHex(c)) is.putback(c); else code = code * 16 + valueHex(c); return code; } default: { int code; if (!isOct(c)) throw DataFormatError("Escape format error"); else if (code = valueOct(c), !is.get(c) || !isOct(c)) is.putback(c); else if (code = code * 8 + valueOct(c), !is.get(c) || !isOct(c)) is.putback(c); else code = code * 8 + valueOct(c); return code; } } } static bool isOct(char c) { return '0' <= c && c <='7'; } static int valueOct(char c) { return c - '0'; } static bool isHex(char c) { return ('0' <= c && c <= '9') || ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z'); } static int valueHex(char c) { if ('0' <= c && c <= '9') return c - '0'; if ('a' <= c && c <= 'z') return c - 'a' + 10; return c - 'A' + 10; } bool escaped; }; /// \brief The graph reader class. /// /// The reader class for the graph input. /// \see \ref GraphWriter /// \see \ref graph-io-page template class GraphReader { public: typedef _Graph Graph; typedef typename Graph::Node Node; typedef typename Graph::Edge Edge; typedef _ReaderTraits ReaderTraits; typedef typename ReaderTraits::DefaultReader DefaultReader; /// \brief Construct a new GraphReader. /// /// Construct a new GraphReader. It reads into the given graph /// and it use the given reader as the default skipper. GraphReader(std::istream& _is, Graph& _graph, const DefaultReader& _reader = DefaultReader()) : is(_is), graph(_graph), nodeSkipper(_reader), edgeSkipper(_reader) {} /// \brief Destruct the graph reader. /// /// Destruct the graph reader. ~GraphReader() { for (typename NodeMapReaders::iterator it = node_map_readers.begin(); it != node_map_readers.end(); ++it) { delete it->second; } for (typename EdgeMapReaders::iterator it = edge_map_readers.begin(); it != edge_map_readers.end(); ++it) { delete it->second; } } /// \brief Add a new node map reader command for the reader. /// /// Add a new node map reader command for the reader. template GraphReader& addNodeMap(std::string name, Map& map) { return addNodeMap, Map>(name, map); } /// \brief Add a new node map reader command for the reader. /// /// Add a new node map reader command for the reader. template GraphReader& addNodeMap(std::string name, Map& map, const Reader& reader = Reader()) { if (node_map_readers.find(name) != node_map_readers.end()) { ErrorMessage msg; msg << "Multiple read rule for node map: " << name; throw IOParameterError(msg.message()); } node_map_readers.insert( make_pair(name, new MapReader(map, reader))); return *this; } /// \brief Add a new node map skipper command for the reader. /// /// Add a new node map skipper command for the reader. template GraphReader& skipNodeMap(std::string name, const Reader& reader = Reader()) { if (node_map_readers.find(name) != node_map_readers.end()) { ErrorMessage msg; msg << "Multiple read rule for node map: " << name; throw IOParameterError(msg.message()); } node_map_readers.insert( make_pair(name, new SkipReader(reader))); return *this; } /// \brief Add a new edge map reader command for the reader. /// /// Add a new edge map reader command for the reader. template GraphReader& addEdgeMap(std::string name, Map& map) { return addEdgeMap, Map>(name, map); } /// \brief Add a new edge map reader command for the reader. /// /// Add a new edge map reader command for the reader. template GraphReader& addEdgeMap(std::string name, Map& map, const Reader& reader = Reader()) { if (edge_map_readers.find(name) != edge_map_readers.end()) { ErrorMessage msg; msg << "Multiple read rule for edge map: " << name; throw IOParameterError(msg.message()); } edge_map_readers.insert( make_pair(name, new MapReader(map, reader))); return *this; } /// \brief Add a new edge map skipper command for the reader. /// /// Add a new edge map skipper command for the reader. template GraphReader& skipEdgeMap(std::string name, const Reader& reader = Reader()) { if (edge_map_readers.find(name) != edge_map_readers.end()) { ErrorMessage msg; msg << "Multiple read rule for edge map: " << name; throw IOParameterError(msg.message()); } edge_map_readers.insert( make_pair(name, new SkipReader(reader))); return *this; } /// \brief Add a new labeled node reader for the reader. /// /// Add a new labeled node reader for the reader. GraphReader& addNode(std::string name, Node& node) { if (node_readers.find(name) != node_readers.end()) { ErrorMessage msg; msg << "Multiple read rule for node: " << name; throw IOParameterError(msg.message()); } node_readers.insert(make_pair(name, &node)); return *this; } /// \brief Add a new labeled edge reader for the reader. /// /// Add a new labeled edge reader for the reader. GraphReader& addEdge(std::string name, Edge& edge) { if (edge_readers.find(name) != edge_readers.end()) { ErrorMessage msg; msg << "Multiple read rule for edge: " << name; throw IOParameterError(msg.message()); } edge_readers.insert(make_pair(name, &edge)); return *this; } /// \brief Executes the reader commands. /// /// Executes the reader commands. void run() { int line_num = 0; std::auto_ptr > nodeInverter; std::auto_ptr > edgeInverter; try { std::string line = readNotEmptyLine(is, line_num); if (line.find("@nodeset") == 0) { line = readNodeSet(line_num, nodeInverter); } if (line.find("@edgeset") == 0) { line = readEdgeSet(line_num, edgeInverter, nodeInverter); } if (line.find("@nodes") == 0) { line = readNodes(line_num, nodeInverter); } if (line.find("@edges") == 0) { line = readEdges(line_num, edgeInverter); } if (line.find("@end") != 0) { throw DataFormatError("Invalid control sequence error"); } } catch (DataFormatError e) { e.line(line_num); throw e; } } private: template class InverterBase; std::string readNodeSet(int& line_num, auto_ptr > & nodeInverter) { std::vector* > index; { std::string line = readNotEmptyLine(is, line_num); std::string id; std::istringstream ls(line); while (ls >> id) { if (id[0] == '#') break; typename NodeMapReaders::iterator it = node_map_readers.find(id); if (it != node_map_readers.end()) { index.push_back(it->second); node_map_readers.erase(it); } else { index.push_back(&nodeSkipper); } } } if (index.size() == 0) { throw DataFormatError("Cannot find node id map"); } nodeInverter = auto_ptr >(index[0]->getInverter()); std::string line; while (line = readNotEmptyLine(is, line_num), line[0] != '@') { Node node = graph.addNode(); std::istringstream ls(line); nodeInverter->read(ls, node); for (int i = 1; i < (int)index.size(); ++i) { index[i]->read(ls, node); } } return line; } std::string readEdgeSet(int& line_num, auto_ptr > & edgeInverter, auto_ptr > & nodeInverter) { std::vector*> index; { std::string line = readNotEmptyLine(is, line_num); std::string id; std::istringstream ls(line); while (ls >> id) { if (id[0] == '#') break; typename EdgeMapReaders::iterator it = edge_map_readers.find(id); if (it != edge_map_readers.end()) { index.push_back(it->second); edge_map_readers.erase(it); } else { index.push_back(&edgeSkipper); } } } if (index.size() == 0) { throw DataFormatError("Cannot find edge id map"); } edgeInverter = auto_ptr >(index[0]->getInverter()); std::string line; while (line = readNotEmptyLine(is, line_num), line[0] != '@') { std::istringstream ls(line); Node source = nodeInverter->read(ls); Node target = nodeInverter->read(ls); Edge edge = graph.addEdge(source, target); edgeInverter->read(ls, edge); for (int i = 1; i < (int)index.size(); ++i) { index[i]->read(ls, edge); } } return line; } std::string readNodes(int& line_num, auto_ptr >& nodeInverter) { std::string line; while (line = readNotEmptyLine(is, line_num), line[0] != '@') { std::istringstream ls(line); std::string name; ls >> name; typename NodeReaders::iterator it = node_readers.find(name); if (it != node_readers.end()) { *(it -> second) = nodeInverter->read(ls); } } return line; } std::string readEdges(int& line_num, auto_ptr >& edgeInverter) { std::string line; while (line = readNotEmptyLine(is, line_num), line[0] != '@') { std::istringstream ls(line); std::string name; ls >> name; typename EdgeReaders::iterator it = edge_readers.find(name); if (it != edge_readers.end()) { *(it -> second) = edgeInverter->read(ls); } } return line; } std::string readNotEmptyLine(std::istream& is, int& line_num) { std::string line; while (++line_num, getline(is, line)) { int vi = line.find_first_not_of(" \t"); if (vi != (int)string::npos && line[vi] != '#') { return line.substr(vi); } } throw DataFormatError("End of stream error"); } // Inverters store and give back the Item from the id, // and may put the ids into a map. template class InverterBase { public: typedef _Item Item; virtual void read(std::istream&, const Item&) = 0; virtual Item read(std::istream&) = 0; }; template class MapReaderInverter : public InverterBase<_Item> { public: typedef _Item Item; typedef _Reader Reader; typedef typename Reader::Value Value; typedef _Map Map; typedef std::map Inverse; Map& map; Reader reader; Inverse inverse; MapReaderInverter(Map& _map, const Reader& _reader) : map(_map), reader(_reader) {} virtual ~MapReaderInverter() {} virtual void read(std::istream& is, const Item& item) { Value value; reader.read(is, value); map.set(item, value); typename Inverse::iterator it = inverse.find(value); if (it == inverse.end()) { inverse.insert(make_pair(value, item)); } else { throw DataFormatError("Multiple ID occurence"); } } virtual Item read(std::istream& is) { Value value; reader.read(is, value); typename Inverse::const_iterator it = inverse.find(value); if (it != inverse.end()) { return it->second; } else { throw DataFormatError("Invalid ID error"); } } }; template class SkipReaderInverter : public InverterBase<_Item> { public: typedef _Item Item; typedef _Reader Reader; typedef typename Reader::Value Value; typedef std::map Inverse; Reader reader; SkipReaderInverter(const Reader& _reader) : reader(_reader) {} virtual ~SkipReaderInverter() {} virtual void read(std::istream& is, const Item& item) { Value value; reader.read(is, value); typename Inverse::iterator it = inverse.find(value); if (it == inverse.end()) { inverse.insert(make_pair(value, item)); } else { throw DataFormatError("Multiple ID occurence error"); } } virtual Item read(std::istream& is) { Value value; reader.read(is, value); typename Inverse::const_iterator it = inverse.find(value); if (it != inverse.end()) { return it->second; } else { throw DataFormatError("Invalid ID error"); } } private: Inverse inverse; }; // Readers template class ReaderBase { public: typedef _Item Item; // virtual ~ReaderBase() {} virtual void read(std::istream& is, const Item& item) = 0; virtual InverterBase<_Item>* getInverter() = 0; }; template class MapReader : public ReaderBase<_Item> { public: typedef _Map Map; typedef _Reader Reader; typedef typename Reader::Value Value; typedef _Item Item; Map& map; Reader reader; MapReader(Map& _map, const Reader& _reader) : map(_map), reader(_reader) {} virtual ~MapReader() {} virtual void read(std::istream& is, const Item& item) { Value value; reader.read(is, value); map.set(item, value); } virtual InverterBase<_Item>* getInverter() { return new MapReaderInverter(map, reader); } }; template class SkipReader : public ReaderBase<_Item> { public: typedef _Reader Reader; typedef typename Reader::Value Value; typedef _Item Item; Reader reader; SkipReader(const Reader& _reader) : reader(_reader) {} virtual ~SkipReader() {} virtual void read(std::istream& is, const Item&) { Value value; reader.read(is, value); } virtual InverterBase* getInverter() { return new SkipReaderInverter(reader); } }; typedef std::map*> NodeMapReaders; NodeMapReaders node_map_readers; typedef std::map*> EdgeMapReaders; EdgeMapReaders edge_map_readers; typedef std::map NodeReaders; NodeReaders node_readers; typedef std::map EdgeReaders; EdgeReaders edge_readers; std::istream& is; Graph& graph; SkipReader nodeSkipper; SkipReader edgeSkipper; }; /// Ready to use reader function. template void readGraph(std::istream& is, Graph &g, CapacityMap& capacity, typename Graph::Node &s, typename Graph::Node &t, CostMap& cost) { GraphReader reader(is, g); reader.addEdgeMap("capacity", capacity); reader.addEdgeMap("cost", cost); reader.addNode("source", s); reader.addNode("target", t); reader.run(); } template void readGraph(std::istream& is, Graph &g, CapacityMap& capacity, typename Graph::Node &s, typename Graph::Node &t) { GraphReader reader(is, g); reader.addEdgeMap("capacity", capacity); reader.addNode("source", s); reader.addNode("target", t); reader.run(); } template void readGraph(std::istream& is, Graph &g, CapacityMap& capacity, typename Graph::Node &s) { GraphReader reader(is, g); reader.addEdgeMap("capacity", capacity); reader.addNode("source", s); reader.run(); } template void readGraph(std::istream& is, Graph &g, CapacityMap& capacity) { GraphReader reader(is, g); reader.addEdgeMap("capacity", capacity); reader.run(); } template void readGraph(std::istream& is, Graph &g) { GraphReader reader(is, g); reader.run(); } } #endif