/* -*- 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 io_group ///\file ///\brief Lemon Graph Format reader. #ifndef LEMON_GRAPH_READER_H #define LEMON_GRAPH_READER_H #include #include #include #include #include #include namespace lemon { /// \addtogroup io_group /// @{ /// \brief Standard ReaderTraits for the GraphReader class. /// /// Standard ReaderTraits for the GraphReader class. /// It defines standard reading method for all type of value. /// \author Balazs Dezso struct DefaultReaderTraits { /// \brief Template class for reading an value. /// /// Template class for reading an value. /// \author Balazs Dezso 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"); } }; /// \brief Returns wheter this name is an ID map name. /// /// Returns wheter this name is an ID map name. static bool idMapName(const std::string& name) { return name == "id"; } /// 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. /// \author Balazs Dezso 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 >> std::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 given file format may contain several maps and labeled nodes or /// edges. /// /// If you read a graph you need not read all the maps and items just those /// that you need. The interface of the \c GraphReader is very similar to /// the GraphWriter but the reading method does not depend on the order the /// given commands. /// /// The reader object suppose that each not readed value does not contain /// whitespaces, therefore it has some extra possibilities to control how /// it should skip the values when the string representation contains spaces. /// /// \code /// GraphReader reader(std::cin, graph); /// \endcode /// /// The \c addNodeMap() function reads a map from the \c \@nodeset section. /// If there is a map that you do not want to read from the file and there is /// whitespace in the string represenation of the values then you should /// call the \c skipNodeMap() template member function with proper /// parameters. /// /// \code /// reader.addNodeMap("x-coord", xCoordMap); /// reader.addNodeMap("y-coord", yCoordMap); /// /// reader.addNodeMap("label", labelMap); /// reader.skipNodeMap("description"); /// /// reader.addNodeMap("color", colorMap); /// \endcode /// /// With the \c addEdgeMap() member function you can give an edge map /// reading command similar to the NodeMaps. /// /// \code /// reader.addEdgeMap("weight", weightMap); /// reader.addEdgeMap("label", labelMap); /// \endcode /// /// With \c addNode() and \c addEdge() functions you can read labeled Nodes /// and Edges. /// /// \code /// reader.addNode("source", sourceNode); /// reader.addNode("target", targetNode); /// /// reader.addEdge("observed", edge); /// \endcode /// /// After you give all read commands you must call the \c run() member /// function, which execute all the commands. /// /// \code /// reader.run(); /// \endcode /// /// \see DefaultReaderTraits /// \see QuotedStringReader /// \see \ref GraphWriter /// \see \ref graph-io-page /// \author Balazs Dezso 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, std::auto_ptr >& nodeInverter) { std::vector* > index; { std::string line = readNotEmptyLine(is, line_num); std::string id; std::istringstream ls(line); while (ls >> id) { 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 (ReaderTraits::idMapName(id) && nodeInverter.get() == 0) { nodeInverter.reset(index.back()->getInverter()); index.back() = nodeInverter.get(); } } } // if (index.size() == 0) { // throw DataFormatError("Cannot find node id map"); // } // nodeInverter = // std::auto_ptr >(index[0]->getInverter()); std::string line; while (line = readNotEmptyLine(is, line_num), line[0] != '@') { Node node = graph.addNode(); std::istringstream ls(line); for (int i = 0; i < (int)index.size(); ++i) { index[i]->read(ls, node); } } return line; } std::string readEdgeSet(int& line_num, std::auto_ptr >& edgeInverter, std::auto_ptr >& nodeInverter) { std::vector*> index; { std::string line = readNotEmptyLine(is, line_num); std::string id; std::istringstream ls(line); while (ls >> id) { 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 (ReaderTraits::idMapName(id) && edgeInverter.get() == 0) { edgeInverter.reset(index.back()->getInverter()); index.back() = edgeInverter.get(); } } } if (nodeInverter.get() == 0) { throw DataFormatError("Cannot find node id map"); } // if (index.size() == 0) { // throw DataFormatError("Cannot find edge id map"); // } // edgeInverter = // std::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); for (int i = 0; i < (int)index.size(); ++i) { index[i]->read(ls, edge); } } return line; } std::string readNodes(int& line_num, std::auto_ptr >& nodeInverter) { std::string line; if (nodeInverter.get() == 0) { throw DataFormatError("Cannot find node id map"); } 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, std::auto_ptr >& edgeInverter) { std::string line; if (edgeInverter.get() == 0) { throw DataFormatError("Cannot find edge id map"); } 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('#'); if (vi != (int)::std::string::npos) { line = line.substr(0, vi); } vi = line.find_first_not_of(" \t"); if (vi != (int)std::string::npos) { std::cerr << "Line: " << line.substr(vi) << std::endl; return line.substr(vi); } } throw DataFormatError("End of stream error"); } template class ReaderBase; template class InverterBase : public ReaderBase<_Item> { public: typedef _Item Item; virtual void read(std::istream&, const Item&) = 0; virtual Item read(std::istream&) = 0; virtual InverterBase<_Item>* getInverter() { return this; } }; 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(std::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(std::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; }; /// \brief Read a graph from the input. /// /// Read a graph from the input. /// \param is The input stream. /// \param g The graph. /// \param capacity The capacity map. /// \param s The source node. /// \param t The target node. /// \param cost The cost map. 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(); } /// \brief Read a graph from the input. /// /// Read a graph from the input. /// \param is The input stream. /// \param g The graph. /// \param capacity The capacity map. /// \param s The source node. /// \param t The target node. 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(); } /// \brief Read a graph from the input. /// /// Read a graph from the input. /// \param is The input stream. /// \param g The graph. /// \param capacity The capacity map. /// \param s The source node. 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(); } /// \brief Read a graph from the input. /// /// Read a graph from the input. /// \param is The input stream. /// \param g The graph. /// \param capacity The capacity map. template void readGraph(std::istream& is, Graph &g, CapacityMap& capacity) { GraphReader reader(is, g); reader.addEdgeMap("capacity", capacity); reader.run(); } /// \brief Read a graph from the input. /// /// Read a graph from the input. /// \param is The input stream. /// \param g The graph. template void readGraph(std::istream& is, Graph &g) { GraphReader reader(is, g); reader.run(); } /// @} } #endif