deba@1037: /* -*- C++ -*- deba@1037: * src/lemon/graph_writer.h - Part of LEMON, a generic C++ optimization library deba@1037: * deba@1037: * Copyright (C) 2004 Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport deba@1037: * (Egervary Combinatorial Optimization Research Group, EGRES). deba@1037: * deba@1037: * Permission to use, modify and distribute this software is granted deba@1037: * provided that this copyright notice appears in all copies. For deba@1037: * precise terms see the accompanying LICENSE file. deba@1037: * deba@1037: * This software is provided "AS IS" with no warranty of any kind, deba@1037: * express or implied, and with no claim as to its suitability for any deba@1037: * purpose. deba@1037: * deba@1037: */ deba@1037: deba@1037: ///\ingroup gio deba@1037: ///\file deba@1037: ///\brief Graph writer. deba@1037: deba@1037: deba@1037: #include deba@1037: #include deba@1037: deba@1037: #include deba@1037: #include deba@1037: deba@1037: #include deba@1037: deba@1037: #include deba@1037: #include deba@1037: deba@1037: deba@1037: namespace lemon { deba@1037: deba@1037: struct DefaultWriterTraits { deba@1037: deba@1037: template deba@1037: struct Writer { deba@1037: typedef _Value Value; deba@1037: deba@1037: void write(std::ostream& os, const Value& value) { deba@1037: os << value << '\t'; deba@1037: } deba@1037: }; deba@1037: deba@1037: }; deba@1037: deba@1037: deba@1037: class QuotedStringWriter { deba@1037: public: deba@1037: typedef std::string Value; deba@1037: deba@1037: QuotedStringWriter(bool _escaped = true) : escaped(_escaped) {} deba@1037: deba@1037: void write(std::ostream& os, const std::string& value) { deba@1037: char c; deba@1037: os << "\""; deba@1037: if (escaped) { deba@1037: ostringstream ls; deba@1037: for (int i = 0; i < value.size(); ++i) { deba@1037: writeEscape(ls, value[i]); deba@1037: } deba@1037: os << ls.str(); deba@1037: } else { deba@1037: os << value; deba@1037: } deba@1037: os << "\""; deba@1037: } deba@1037: deba@1037: private: deba@1037: deba@1037: static void writeEscape(std::ostream& os, char c) { deba@1037: switch (c) { deba@1037: case '\\': deba@1037: os << "\\\\"; deba@1037: return; deba@1037: case '\"': deba@1037: os << "\\\""; deba@1037: return; deba@1037: case '\'': deba@1037: os << "\\\'"; deba@1037: return; deba@1037: case '\?': deba@1037: os << "\\\?"; deba@1037: return; deba@1037: case '\a': deba@1037: os << "\\a"; deba@1037: return; deba@1037: case '\b': deba@1037: os << "\\b"; deba@1037: return; deba@1037: case '\f': deba@1037: os << "\\f"; deba@1037: return; deba@1037: case '\r': deba@1037: os << "\\r"; deba@1037: return; deba@1037: case '\n': deba@1037: os << "\\n"; deba@1037: return; deba@1037: case '\t': deba@1037: os << "\\t"; deba@1037: return; deba@1037: case '\v': deba@1037: os << "\\v"; deba@1037: return; deba@1037: default: deba@1037: if (c < 0x20) { deba@1037: os << '\\' << oct << (int)c; deba@1037: } else { deba@1037: os << c; deba@1037: } deba@1037: return; deba@1037: } deba@1037: } deba@1037: private: deba@1037: bool escaped; deba@1037: }; deba@1037: deba@1037: // Graph writer deba@1037: deba@1037: template deba@1037: class GraphWriter { deba@1037: public: deba@1037: deba@1037: typedef _Graph Graph; deba@1037: typedef typename Graph::Node Node; deba@1037: typedef typename Graph::NodeIt NodeIt; deba@1037: typedef typename Graph::Edge Edge; deba@1037: typedef typename Graph::EdgeIt EdgeIt; deba@1037: deba@1037: typedef _WriterTraits WriterTraits; deba@1037: deba@1037: GraphWriter(std::ostream& _os, Graph& _graph) : os(_os), graph(_graph) {} deba@1037: deba@1037: deba@1037: ~GraphWriter() { deba@1037: deba@1037: for (typename NodeMapWriters::iterator it = node_map_writers.begin(); it != node_map_writers.end(); ++it) { deba@1037: delete it->second; deba@1037: } deba@1037: deba@1037: for (typename EdgeMapWriters::iterator it = edge_map_writers.begin(); it != edge_map_writers.end(); ++it) { deba@1037: delete it->second; deba@1037: } deba@1037: deba@1037: } deba@1037: deba@1037: // Node map rules deba@1037: deba@1037: template deba@1037: GraphWriter& writeNodeMap(std::string name, const Map& map) { deba@1037: return writeNodeMap, Map>(name, map); deba@1037: } deba@1037: deba@1037: template deba@1037: GraphWriter& writeNodeMap(std::string name, const Map& map, const Writer& writer = Writer()) { deba@1037: // if (node_map_writers.find(name) != node_map_writers.end()) { deba@1037: // throw Exception() << "Multiple write rule for node map: " << name; deba@1037: // } deba@1037: node_map_writers.push_back(make_pair(name, new MapWriter(map, writer))); deba@1037: return *this; deba@1037: } deba@1037: deba@1037: // Edge map rules deba@1037: deba@1037: template deba@1037: GraphWriter& writeEdgeMap(std::string name, const Map& map) { deba@1037: return writeEdgeMap, Map>(name, map); deba@1037: } deba@1037: deba@1037: deba@1037: template deba@1037: GraphWriter& writeEdgeMap(std::string name, const Map& map, const Writer& writer = Writer()) { deba@1037: // if (edge_map_writers.find(name) != edge_map_writers.end()) { deba@1037: // throw Exception() << "Multiple write rule for edge map: " << name; deba@1037: // } deba@1037: edge_map_writers.push_back(make_pair(name, new MapWriter(map, writer))); deba@1037: return *this; deba@1037: } deba@1037: deba@1037: // Node rules deba@1037: GraphWriter& writeNode(std::string name, const Node& node) { deba@1037: // if (node_writers.find(name) != node_writers.end()) { deba@1037: // throw Exception() << "Multiple write rule for node"; deba@1037: // } deba@1037: node_writers.push_back(make_pair(name, node)); deba@1037: } deba@1037: deba@1037: // Edge rules deba@1037: deba@1037: GraphWriter& writeEdge(std::string name, const Edge& edge) { deba@1037: // if (edge_writers.find(name) != edge_writers.end()) { deba@1037: // throw Exception() << "Multiple write rule for edge"; deba@1037: // } deba@1037: edge_writers.push_back(make_pair(name, edge)); deba@1037: } deba@1037: deba@1037: void write() { deba@1037: writeNodeSet(); deba@1037: writeEdgeSet(); deba@1037: writeNodes(); deba@1037: writeEdges(); deba@1037: os << "@end" << std::endl; deba@1037: } deba@1037: deba@1037: private: deba@1037: deba@1037: void writeNodeSet() { deba@1037: if (node_map_writers.size() == 0) return; deba@1037: os << "@nodeset" << std::endl; deba@1037: for (int i = 0; i < node_map_writers.size(); ++i) { deba@1037: os << node_map_writers[i].first << '\t'; deba@1037: } deba@1037: os << std::endl; deba@1037: for (NodeIt it(graph); it != INVALID; ++it) { deba@1037: for (int i = 0; i < node_map_writers.size(); ++i) { deba@1037: node_map_writers[i].second->write(os, it); deba@1037: } deba@1037: os << std::endl; deba@1037: } deba@1037: deba@1037: } deba@1037: deba@1037: void writeEdgeSet() { deba@1037: if (edge_map_writers.size() == 0) return; deba@1037: if (node_map_writers.size() == 0) { deba@1037: throw Exception() << "Missing node id map"; deba@1037: } deba@1037: os << "@edgeset" << std::endl; deba@1037: os << "\t\t"; deba@1037: for (int i = 0; i < edge_map_writers.size(); ++i) { deba@1037: os << edge_map_writers[i].first << '\t'; deba@1037: } deba@1037: os << std::endl; deba@1037: for (EdgeIt it(graph); it != INVALID; ++it) { deba@1037: node_map_writers[0].second->write(os, graph.source(it)); deba@1037: node_map_writers[0].second->write(os, graph.target(it)); deba@1037: for (int i = 0; i < edge_map_writers.size(); ++i) { deba@1037: edge_map_writers[i].second->write(os, it); deba@1037: } deba@1037: os << std::endl; deba@1037: } deba@1037: } deba@1037: deba@1037: void writeNodes() { deba@1037: if (node_writers.size() == 0) return; deba@1037: if (node_map_writers.size() == 0) { deba@1037: throw Exception() << "Missing node id map"; deba@1037: } deba@1037: os << "@nodes" << std::endl; deba@1037: for (int i = 0; i < node_writers.size(); ++i) { deba@1037: os << node_writers[i].first << '\t'; deba@1037: node_map_writers[0].second->write(os, node_writers[i].second); deba@1037: os << std::endl; deba@1037: } deba@1037: } deba@1037: deba@1037: void writeEdges() { deba@1037: if (edge_writers.size() == 0) return; deba@1037: if (edge_map_writers.size() == 0) { deba@1037: throw Exception() << "Missing edge id map"; deba@1037: } deba@1037: os << "@edges" << std::endl; deba@1037: for (int i = 0; i < edge_writers.size(); ++i) { deba@1037: os << edge_writers[i].first << '\t'; deba@1037: edge_map_writers[0].second->write(os, edge_writers[i].second); deba@1037: os << std::endl; deba@1037: } deba@1037: } deba@1037: deba@1037: // Writers deba@1037: deba@1037: template deba@1037: class WriterBase { deba@1037: public: deba@1037: typedef _Item Item; deba@1037: virtual void write(std::ostream&, const Item&) = 0; deba@1037: }; deba@1037: deba@1037: template deba@1037: class MapWriter : public WriterBase<_Item> { deba@1037: public: deba@1037: typedef _Map Map; deba@1037: typedef _Writer Writer; deba@1037: typedef typename Writer::Value Value; deba@1037: typedef _Item Item; deba@1037: deba@1037: const Map& map; deba@1037: Writer writer; deba@1037: deba@1037: MapWriter(const Map& _map, const Writer& _writer) deba@1037: : map(_map), writer(_writer) {} deba@1037: deba@1037: deba@1037: virtual void write(std::ostream& os, const Item& item) { deba@1037: Value value; deba@1037: writer.write(os, map[item]); deba@1037: } deba@1037: deba@1037: }; deba@1037: deba@1037: deba@1037: deba@1037: typedef std::vector< std::pair*> > NodeMapWriters; deba@1037: NodeMapWriters node_map_writers; deba@1037: deba@1037: typedef std::vector< std::pair*> > EdgeMapWriters; deba@1037: EdgeMapWriters edge_map_writers; deba@1037: deba@1037: typedef std::vector > NodeWriters; deba@1037: NodeWriters node_writers; deba@1037: deba@1037: typedef std::vector > EdgeWriters; deba@1037: EdgeWriters edge_writers; deba@1037: deba@1037: std::ostream& os; deba@1037: Graph& graph; deba@1037: deba@1037: }; deba@1037: deba@1037: deba@1037: }