alpar@209: /* -*- mode: C++; indent-tabs-mode: nil; -*- deba@127: * alpar@209: * This file is a part of LEMON, a generic C++ optimization library. deba@127: * alpar@440: * Copyright (C) 2003-2009 deba@127: * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport deba@127: * (Egervary Research Group on Combinatorial Optimization, EGRES). deba@127: * deba@127: * Permission to use, modify and distribute this software is granted deba@127: * provided that this copyright notice appears in all copies. For deba@127: * precise terms see the accompanying LICENSE file. deba@127: * deba@127: * This software is provided "AS IS" with no warranty of any kind, deba@127: * express or implied, and with no claim as to its suitability for any deba@127: * purpose. deba@127: * deba@127: */ deba@127: deba@127: ///\ingroup lemon_io deba@127: ///\file ladanyi@236: ///\brief \ref lgf-format "LEMON Graph Format" writer. deba@127: deba@127: deba@127: #ifndef LEMON_LGF_WRITER_H deba@127: #define LEMON_LGF_WRITER_H deba@127: deba@127: #include deba@127: #include deba@127: #include deba@127: deba@127: #include deba@127: deba@127: #include deba@127: #include deba@127: deba@220: #include deba@220: #include deba@127: deba@248: #include deba@248: #include deba@248: deba@127: namespace lemon { deba@127: deba@127: namespace _writer_bits { deba@127: deba@127: template deba@127: struct DefaultConverter { deba@127: std::string operator()(const Value& value) { alpar@209: std::ostringstream os; alpar@209: os << value; alpar@209: return os.str(); deba@127: } deba@127: }; deba@127: deba@127: template deba@127: bool operator<(const T&, const T&) { deba@290: throw FormatError("Label map is not comparable"); deba@127: } deba@127: deba@127: template deba@127: class MapLess { deba@127: public: deba@127: typedef _Map Map; deba@127: typedef typename Map::Key Item; deba@127: deba@127: private: deba@127: const Map& _map; alpar@209: deba@127: public: deba@127: MapLess(const Map& map) : _map(map) {} deba@127: deba@127: bool operator()(const Item& left, const Item& right) { alpar@209: return _map[left] < _map[right]; deba@127: } deba@127: }; deba@127: deba@165: template deba@165: class GraphArcMapLess { deba@165: public: deba@165: typedef _Map Map; deba@165: typedef _Graph Graph; deba@165: typedef typename Graph::Edge Item; deba@165: deba@165: private: deba@165: const Graph& _graph; deba@165: const Map& _map; alpar@209: deba@165: public: alpar@209: GraphArcMapLess(const Graph& graph, const Map& map) alpar@209: : _graph(graph), _map(map) {} deba@165: deba@165: bool operator()(const Item& left, const Item& right) { alpar@209: return _map[_graph.direct(left, _dir)] < alpar@209: _map[_graph.direct(right, _dir)]; deba@165: } deba@165: }; deba@165: alpar@209: template deba@127: class MapStorageBase { deba@127: public: deba@127: typedef _Item Item; deba@127: deba@127: public: deba@127: MapStorageBase() {} deba@127: virtual ~MapStorageBase() {} deba@127: deba@127: virtual std::string get(const Item& item) = 0; deba@127: virtual void sort(std::vector&) = 0; deba@127: }; deba@127: alpar@209: template > deba@127: class MapStorage : public MapStorageBase<_Item> { deba@127: public: deba@127: typedef _Map Map; deba@127: typedef _Converter Converter; deba@127: typedef _Item Item; alpar@209: deba@127: private: deba@127: const Map& _map; deba@127: Converter _converter; deba@127: deba@127: public: alpar@209: MapStorage(const Map& map, const Converter& converter = Converter()) alpar@209: : _map(map), _converter(converter) {} deba@127: virtual ~MapStorage() {} deba@127: deba@127: virtual std::string get(const Item& item) { alpar@209: return _converter(_map[item]); deba@127: } deba@127: virtual void sort(std::vector& items) { alpar@209: MapLess less(_map); alpar@209: std::sort(items.begin(), items.end(), less); deba@127: } deba@127: }; deba@127: alpar@209: template > deba@165: class GraphArcMapStorage : public MapStorageBase { deba@165: public: deba@165: typedef _Map Map; deba@165: typedef _Converter Converter; deba@165: typedef _Graph Graph; deba@165: typedef typename Graph::Edge Item; deba@165: static const bool dir = _dir; alpar@209: deba@165: private: deba@165: const Graph& _graph; deba@165: const Map& _map; deba@165: Converter _converter; deba@165: deba@165: public: alpar@209: GraphArcMapStorage(const Graph& graph, const Map& map, alpar@209: const Converter& converter = Converter()) alpar@209: : _graph(graph), _map(map), _converter(converter) {} deba@165: virtual ~GraphArcMapStorage() {} deba@165: deba@165: virtual std::string get(const Item& item) { alpar@209: return _converter(_map[_graph.direct(item, dir)]); deba@165: } deba@165: virtual void sort(std::vector& items) { alpar@209: GraphArcMapLess less(_graph, _map); alpar@209: std::sort(items.begin(), items.end(), less); deba@165: } deba@165: }; deba@165: deba@127: class ValueStorageBase { deba@127: public: deba@127: ValueStorageBase() {} deba@127: virtual ~ValueStorageBase() {} deba@127: alpar@209: virtual std::string get() = 0; deba@127: }; deba@127: deba@127: template > deba@127: class ValueStorage : public ValueStorageBase { deba@127: public: deba@127: typedef _Value Value; deba@127: typedef _Converter Converter; deba@127: deba@127: private: deba@127: const Value& _value; deba@127: Converter _converter; deba@127: deba@127: public: deba@127: ValueStorage(const Value& value, const Converter& converter = Converter()) kpeter@212: : _value(value), _converter(converter) {} deba@127: deba@127: virtual std::string get() { alpar@209: return _converter(_value); deba@127: } deba@127: }; deba@127: deba@127: template deba@127: struct MapLookUpConverter { deba@127: const std::map& _map; alpar@209: alpar@209: MapLookUpConverter(const std::map& map) alpar@209: : _map(map) {} alpar@209: deba@127: std::string operator()(const Value& str) { alpar@209: typename std::map::const_iterator it = alpar@209: _map.find(str); alpar@209: if (it == _map.end()) { deba@290: throw FormatError("Item not found"); alpar@209: } alpar@209: return it->second; deba@127: } deba@127: }; deba@127: deba@165: template deba@165: struct GraphArcLookUpConverter { deba@165: const Graph& _graph; deba@165: const std::map& _map; alpar@209: alpar@209: GraphArcLookUpConverter(const Graph& graph, alpar@209: const std::map& map) alpar@209: : _graph(graph), _map(map) {} alpar@209: deba@165: std::string operator()(const typename Graph::Arc& val) { alpar@209: typename std::map alpar@209: ::const_iterator it = _map.find(val); alpar@209: if (it == _map.end()) { deba@290: throw FormatError("Item not found"); alpar@209: } alpar@209: return (_graph.direction(val) ? '+' : '-') + it->second; deba@165: } deba@165: }; deba@165: deba@197: inline bool isWhiteSpace(char c) { alpar@209: return c == ' ' || c == '\t' || c == '\v' || alpar@209: c == '\n' || c == '\r' || c == '\f'; deba@127: } deba@127: deba@197: inline bool isEscaped(char c) { alpar@209: return c == '\\' || c == '\"' || c == '\'' || alpar@209: c == '\a' || c == '\b'; deba@127: } deba@127: deba@197: inline static void writeEscape(std::ostream& os, char c) { deba@127: switch (c) { deba@127: case '\\': alpar@209: os << "\\\\"; alpar@209: return; deba@127: case '\"': alpar@209: os << "\\\""; alpar@209: return; deba@127: case '\a': alpar@209: os << "\\a"; alpar@209: return; deba@127: case '\b': alpar@209: os << "\\b"; alpar@209: return; deba@127: case '\f': alpar@209: os << "\\f"; alpar@209: return; deba@127: case '\r': alpar@209: os << "\\r"; alpar@209: return; deba@127: case '\n': alpar@209: os << "\\n"; alpar@209: return; deba@127: case '\t': alpar@209: os << "\\t"; alpar@209: return; deba@127: case '\v': alpar@209: os << "\\v"; alpar@209: return; deba@127: default: alpar@209: if (c < 0x20) { alpar@209: std::ios::fmtflags flags = os.flags(); alpar@209: os << '\\' << std::oct << static_cast(c); alpar@209: os.flags(flags); alpar@209: } else { alpar@209: os << c; alpar@209: } alpar@209: return; alpar@209: } deba@127: } deba@127: deba@197: inline bool requireEscape(const std::string& str) { alpar@156: if (str.empty() || str[0] == '@') return true; deba@127: std::istringstream is(str); deba@127: char c; deba@127: while (is.get(c)) { alpar@209: if (isWhiteSpace(c) || isEscaped(c)) { alpar@209: return true; alpar@209: } deba@127: } deba@127: return false; deba@127: } alpar@209: deba@197: inline std::ostream& writeToken(std::ostream& os, const std::string& str) { deba@127: deba@127: if (requireEscape(str)) { alpar@209: os << '\"'; alpar@209: for (std::string::const_iterator it = str.begin(); alpar@209: it != str.end(); ++it) { alpar@209: writeEscape(os, *it); alpar@209: } alpar@209: os << '\"'; deba@127: } else { alpar@209: os << str; deba@127: } deba@127: return os; deba@127: } deba@127: deba@248: class Section { deba@248: public: deba@248: virtual ~Section() {} deba@248: virtual void process(std::ostream& os) = 0; deba@248: }; deba@248: deba@248: template deba@248: class LineSection : public Section { deba@248: private: deba@248: deba@248: Functor _functor; deba@248: deba@248: public: deba@248: deba@248: LineSection(const Functor& functor) : _functor(functor) {} deba@248: virtual ~LineSection() {} deba@248: deba@248: virtual void process(std::ostream& os) { deba@248: std::string line; deba@248: while (!(line = _functor()).empty()) os << line << std::endl; deba@248: } deba@248: }; deba@248: deba@248: template deba@248: class StreamSection : public Section { deba@248: private: deba@248: deba@248: Functor _functor; deba@248: deba@248: public: deba@248: deba@248: StreamSection(const Functor& functor) : _functor(functor) {} deba@248: virtual ~StreamSection() {} deba@248: deba@248: virtual void process(std::ostream& os) { deba@248: _functor(os); deba@248: } deba@248: }; deba@248: deba@127: } deba@190: deba@190: template deba@190: class DigraphWriter; deba@190: deba@190: template kpeter@293: DigraphWriter digraphWriter(const Digraph& digraph, kpeter@487: std::ostream& os = std::cout); deba@190: template kpeter@293: DigraphWriter digraphWriter(const Digraph& digraph, kpeter@487: const std::string& fn); deba@190: deba@190: template kpeter@293: DigraphWriter digraphWriter(const Digraph& digraph, kpeter@487: const char* fn); kpeter@487: alpar@209: alpar@156: /// \ingroup lemon_io alpar@209: /// kpeter@192: /// \brief \ref lgf-format "LGF" writer for directed graphs alpar@156: /// alpar@156: /// This utility writes an \ref lgf-format "LGF" file. alpar@156: /// alpar@156: /// The writing method does a batch processing. The user creates a alpar@156: /// writer object, then various writing rules can be added to the alpar@156: /// writer, and eventually the writing is executed with the \c run() alpar@156: /// member function. A map writing rule can be added to the writer alpar@156: /// with the \c nodeMap() or \c arcMap() members. An optional deba@163: /// converter parameter can also be added as a standard functor kpeter@192: /// converting from the value type of the map to \c std::string. If it kpeter@192: /// is set, it will determine how the value type of the map is written to deba@163: /// the output stream. If the functor is not set, then a default deba@163: /// conversion will be used. The \c attribute(), \c node() and \c deba@163: /// arc() functions are used to add attribute writing rules. alpar@156: /// alpar@156: ///\code kpeter@293: /// DigraphWriter(digraph, std::cout). kpeter@192: /// nodeMap("coordinates", coord_map). kpeter@192: /// nodeMap("size", size). kpeter@192: /// nodeMap("title", title). kpeter@192: /// arcMap("capacity", cap_map). kpeter@192: /// node("source", src). kpeter@192: /// node("target", trg). kpeter@192: /// attribute("caption", caption). kpeter@192: /// run(); alpar@156: ///\endcode alpar@156: /// alpar@156: /// alpar@156: /// By default, the writer does not write additional captions to the alpar@156: /// sections, but they can be give as an optional parameter of alpar@156: /// the \c nodes(), \c arcs() or \c alpar@156: /// attributes() functions. alpar@156: /// alpar@156: /// The \c skipNodes() and \c skipArcs() functions forbid the deba@163: /// writing of the sections. If two arc sections should be written deba@163: /// to the output, it can be done in two passes, the first pass deba@163: /// writes the node section and the first arc section, then the deba@163: /// second pass skips the node section and writes just the arc deba@163: /// section to the stream. The output stream can be retrieved with deba@163: /// the \c ostream() function, hence the second pass can append its deba@163: /// output to the output of the first pass. kpeter@559: template deba@127: class DigraphWriter { deba@127: public: deba@127: kpeter@559: typedef GR Digraph; deba@148: TEMPLATE_DIGRAPH_TYPEDEFS(Digraph); alpar@209: deba@127: private: deba@127: deba@127: deba@127: std::ostream* _os; deba@127: bool local_os; deba@127: deba@190: const Digraph& _digraph; deba@127: deba@127: std::string _nodes_caption; deba@127: std::string _arcs_caption; deba@127: std::string _attributes_caption; alpar@209: deba@127: typedef std::map NodeIndex; deba@127: NodeIndex _node_index; deba@127: typedef std::map ArcIndex; deba@127: ArcIndex _arc_index; deba@127: alpar@209: typedef std::vector* > > NodeMaps; alpar@209: NodeMaps _node_maps; deba@127: alpar@209: typedef std::vector* > >ArcMaps; deba@127: ArcMaps _arc_maps; deba@127: alpar@209: typedef std::vector > Attributes; deba@127: Attributes _attributes; deba@127: deba@127: bool _skip_nodes; deba@127: bool _skip_arcs; deba@127: deba@127: public: deba@127: alpar@156: /// \brief Constructor alpar@156: /// alpar@156: /// Construct a directed graph writer, which writes to the given alpar@156: /// output stream. kpeter@293: DigraphWriter(const Digraph& digraph, std::ostream& os = std::cout) kpeter@293: : _os(&os), local_os(false), _digraph(digraph), alpar@209: _skip_nodes(false), _skip_arcs(false) {} deba@127: alpar@156: /// \brief Constructor alpar@156: /// alpar@156: /// Construct a directed graph writer, which writes to the given alpar@156: /// output file. kpeter@293: DigraphWriter(const Digraph& digraph, const std::string& fn) deba@127: : _os(new std::ofstream(fn.c_str())), local_os(true), _digraph(digraph), deba@290: _skip_nodes(false), _skip_arcs(false) { deba@295: if (!(*_os)) { deba@295: delete _os; deba@295: throw IoError("Cannot write file", fn); deba@295: } deba@290: } deba@127: alpar@156: /// \brief Constructor alpar@156: /// alpar@156: /// Construct a directed graph writer, which writes to the given alpar@156: /// output file. kpeter@293: DigraphWriter(const Digraph& digraph, const char* fn) deba@127: : _os(new std::ofstream(fn)), local_os(true), _digraph(digraph), deba@290: _skip_nodes(false), _skip_arcs(false) { deba@295: if (!(*_os)) { deba@295: delete _os; deba@295: throw IoError("Cannot write file", fn); deba@295: } deba@290: } deba@127: alpar@156: /// \brief Destructor deba@127: ~DigraphWriter() { alpar@209: for (typename NodeMaps::iterator it = _node_maps.begin(); alpar@209: it != _node_maps.end(); ++it) { alpar@209: delete it->second; deba@127: } deba@127: alpar@209: for (typename ArcMaps::iterator it = _arc_maps.begin(); alpar@209: it != _arc_maps.end(); ++it) { alpar@209: delete it->second; deba@127: } deba@127: alpar@209: for (typename Attributes::iterator it = _attributes.begin(); alpar@209: it != _attributes.end(); ++it) { alpar@209: delete it->second; deba@127: } deba@127: deba@127: if (local_os) { alpar@209: delete _os; deba@127: } deba@127: } deba@127: deba@127: private: deba@190: kpeter@487: template kpeter@487: friend DigraphWriter digraphWriter(const DGR& digraph, kpeter@487: std::ostream& os); kpeter@487: template kpeter@487: friend DigraphWriter digraphWriter(const DGR& digraph, kpeter@487: const std::string& fn); kpeter@487: template kpeter@487: friend DigraphWriter digraphWriter(const DGR& digraph, kpeter@487: const char *fn); deba@190: alpar@209: DigraphWriter(DigraphWriter& other) deba@190: : _os(other._os), local_os(other.local_os), _digraph(other._digraph), alpar@209: _skip_nodes(other._skip_nodes), _skip_arcs(other._skip_arcs) { deba@190: deba@190: other._os = 0; deba@190: other.local_os = false; deba@190: deba@190: _node_index.swap(other._node_index); deba@190: _arc_index.swap(other._arc_index); deba@190: deba@190: _node_maps.swap(other._node_maps); deba@190: _arc_maps.swap(other._arc_maps); deba@190: _attributes.swap(other._attributes); deba@190: deba@190: _nodes_caption = other._nodes_caption; deba@190: _arcs_caption = other._arcs_caption; deba@190: _attributes_caption = other._attributes_caption; deba@190: } alpar@209: deba@127: DigraphWriter& operator=(const DigraphWriter&); deba@127: deba@127: public: deba@127: alpar@156: /// \name Writing rules alpar@156: /// @{ alpar@209: kpeter@192: /// \brief Node map writing rule alpar@156: /// kpeter@192: /// Add a node map writing rule to the writer. deba@127: template deba@127: DigraphWriter& nodeMap(const std::string& caption, const Map& map) { deba@127: checkConcept, Map>(); alpar@209: _writer_bits::MapStorageBase* storage = alpar@209: new _writer_bits::MapStorage(map); deba@127: _node_maps.push_back(std::make_pair(caption, storage)); deba@127: return *this; deba@127: } deba@127: alpar@156: /// \brief Node map writing rule alpar@156: /// alpar@156: /// Add a node map writing rule with specialized converter to the alpar@156: /// writer. deba@127: template alpar@209: DigraphWriter& nodeMap(const std::string& caption, const Map& map, alpar@209: const Converter& converter = Converter()) { deba@127: checkConcept, Map>(); alpar@209: _writer_bits::MapStorageBase* storage = alpar@209: new _writer_bits::MapStorage(map, converter); deba@127: _node_maps.push_back(std::make_pair(caption, storage)); deba@127: return *this; deba@127: } deba@127: alpar@156: /// \brief Arc map writing rule alpar@156: /// alpar@156: /// Add an arc map writing rule to the writer. deba@127: template deba@127: DigraphWriter& arcMap(const std::string& caption, const Map& map) { deba@127: checkConcept, Map>(); alpar@209: _writer_bits::MapStorageBase* storage = alpar@209: new _writer_bits::MapStorage(map); deba@127: _arc_maps.push_back(std::make_pair(caption, storage)); deba@127: return *this; deba@127: } deba@127: alpar@156: /// \brief Arc map writing rule alpar@156: /// alpar@156: /// Add an arc map writing rule with specialized converter to the alpar@156: /// writer. deba@127: template alpar@209: DigraphWriter& arcMap(const std::string& caption, const Map& map, alpar@209: const Converter& converter = Converter()) { deba@127: checkConcept, Map>(); alpar@209: _writer_bits::MapStorageBase* storage = alpar@209: new _writer_bits::MapStorage(map, converter); deba@127: _arc_maps.push_back(std::make_pair(caption, storage)); deba@127: return *this; deba@127: } deba@127: alpar@156: /// \brief Attribute writing rule alpar@156: /// alpar@156: /// Add an attribute writing rule to the writer. deba@127: template deba@127: DigraphWriter& attribute(const std::string& caption, const Value& value) { alpar@209: _writer_bits::ValueStorageBase* storage = alpar@209: new _writer_bits::ValueStorage(value); deba@127: _attributes.push_back(std::make_pair(caption, storage)); deba@127: return *this; deba@127: } deba@127: alpar@156: /// \brief Attribute writing rule alpar@156: /// alpar@156: /// Add an attribute writing rule with specialized converter to the alpar@156: /// writer. deba@127: template alpar@209: DigraphWriter& attribute(const std::string& caption, const Value& value, alpar@209: const Converter& converter = Converter()) { alpar@209: _writer_bits::ValueStorageBase* storage = alpar@209: new _writer_bits::ValueStorage(value, converter); deba@127: _attributes.push_back(std::make_pair(caption, storage)); deba@127: return *this; deba@127: } deba@127: alpar@156: /// \brief Node writing rule alpar@156: /// alpar@156: /// Add a node writing rule to the writer. deba@127: DigraphWriter& node(const std::string& caption, const Node& node) { deba@127: typedef _writer_bits::MapLookUpConverter Converter; deba@127: Converter converter(_node_index); alpar@209: _writer_bits::ValueStorageBase* storage = alpar@209: new _writer_bits::ValueStorage(node, converter); deba@127: _attributes.push_back(std::make_pair(caption, storage)); deba@127: return *this; deba@127: } deba@127: alpar@156: /// \brief Arc writing rule alpar@156: /// alpar@156: /// Add an arc writing rule to writer. deba@127: DigraphWriter& arc(const std::string& caption, const Arc& arc) { deba@127: typedef _writer_bits::MapLookUpConverter Converter; deba@127: Converter converter(_arc_index); alpar@209: _writer_bits::ValueStorageBase* storage = alpar@209: new _writer_bits::ValueStorage(arc, converter); deba@127: _attributes.push_back(std::make_pair(caption, storage)); deba@127: return *this; deba@127: } deba@127: kpeter@192: /// \name Section captions alpar@156: /// @{ alpar@156: kpeter@192: /// \brief Add an additional caption to the \c \@nodes section alpar@156: /// kpeter@192: /// Add an additional caption to the \c \@nodes section. deba@127: DigraphWriter& nodes(const std::string& caption) { deba@127: _nodes_caption = caption; deba@127: return *this; deba@127: } deba@127: kpeter@192: /// \brief Add an additional caption to the \c \@arcs section alpar@156: /// kpeter@192: /// Add an additional caption to the \c \@arcs section. deba@127: DigraphWriter& arcs(const std::string& caption) { deba@127: _arcs_caption = caption; deba@127: return *this; deba@127: } deba@127: kpeter@192: /// \brief Add an additional caption to the \c \@attributes section alpar@156: /// kpeter@192: /// Add an additional caption to the \c \@attributes section. deba@127: DigraphWriter& attributes(const std::string& caption) { deba@127: _attributes_caption = caption; deba@127: return *this; deba@127: } deba@127: alpar@156: /// \name Skipping section alpar@156: /// @{ alpar@156: alpar@156: /// \brief Skip writing the node set alpar@156: /// kpeter@192: /// The \c \@nodes section will not be written to the stream. deba@127: DigraphWriter& skipNodes() { deba@127: LEMON_ASSERT(!_skip_nodes, "Multiple usage of skipNodes() member"); deba@185: _skip_nodes = true; deba@127: return *this; deba@127: } deba@127: alpar@156: /// \brief Skip writing arc set alpar@156: /// kpeter@192: /// The \c \@arcs section will not be written to the stream. deba@127: DigraphWriter& skipArcs() { deba@127: LEMON_ASSERT(!_skip_arcs, "Multiple usage of skipArcs() member"); deba@185: _skip_arcs = true; deba@127: return *this; deba@127: } deba@127: alpar@156: /// @} alpar@156: deba@127: private: deba@127: deba@127: void writeNodes() { deba@127: _writer_bits::MapStorageBase* label = 0; deba@127: for (typename NodeMaps::iterator it = _node_maps.begin(); alpar@209: it != _node_maps.end(); ++it) { deba@127: if (it->first == "label") { alpar@209: label = it->second; alpar@209: break; alpar@209: } deba@127: } deba@127: deba@127: *_os << "@nodes"; deba@127: if (!_nodes_caption.empty()) { alpar@209: _writer_bits::writeToken(*_os << ' ', _nodes_caption); deba@127: } deba@127: *_os << std::endl; deba@127: deba@127: if (label == 0) { alpar@209: *_os << "label" << '\t'; deba@127: } deba@127: for (typename NodeMaps::iterator it = _node_maps.begin(); alpar@209: it != _node_maps.end(); ++it) { alpar@209: _writer_bits::writeToken(*_os, it->first) << '\t'; deba@127: } deba@127: *_os << std::endl; deba@127: deba@127: std::vector nodes; deba@127: for (NodeIt n(_digraph); n != INVALID; ++n) { alpar@209: nodes.push_back(n); deba@127: } alpar@209: deba@127: if (label == 0) { alpar@209: IdMap id_map(_digraph); alpar@209: _writer_bits::MapLess > id_less(id_map); alpar@209: std::sort(nodes.begin(), nodes.end(), id_less); deba@127: } else { alpar@209: label->sort(nodes); deba@127: } deba@127: deba@127: for (int i = 0; i < static_cast(nodes.size()); ++i) { alpar@209: Node n = nodes[i]; alpar@209: if (label == 0) { alpar@209: std::ostringstream os; alpar@209: os << _digraph.id(n); alpar@209: _writer_bits::writeToken(*_os, os.str()); alpar@209: *_os << '\t'; alpar@209: _node_index.insert(std::make_pair(n, os.str())); alpar@209: } alpar@209: for (typename NodeMaps::iterator it = _node_maps.begin(); alpar@209: it != _node_maps.end(); ++it) { alpar@209: std::string value = it->second->get(n); alpar@209: _writer_bits::writeToken(*_os, value); alpar@209: if (it->first == "label") { alpar@209: _node_index.insert(std::make_pair(n, value)); alpar@209: } alpar@209: *_os << '\t'; alpar@209: } alpar@209: *_os << std::endl; deba@127: } deba@127: } deba@127: deba@185: void createNodeIndex() { deba@185: _writer_bits::MapStorageBase* label = 0; deba@185: for (typename NodeMaps::iterator it = _node_maps.begin(); alpar@209: it != _node_maps.end(); ++it) { deba@185: if (it->first == "label") { alpar@209: label = it->second; alpar@209: break; alpar@209: } deba@185: } deba@185: deba@185: if (label == 0) { alpar@209: for (NodeIt n(_digraph); n != INVALID; ++n) { alpar@209: std::ostringstream os; alpar@209: os << _digraph.id(n); alpar@209: _node_index.insert(std::make_pair(n, os.str())); alpar@209: } deba@185: } else { alpar@209: for (NodeIt n(_digraph); n != INVALID; ++n) { alpar@209: std::string value = label->get(n); alpar@209: _node_index.insert(std::make_pair(n, value)); alpar@209: } deba@185: } deba@185: } deba@185: deba@127: void writeArcs() { deba@127: _writer_bits::MapStorageBase* label = 0; deba@127: for (typename ArcMaps::iterator it = _arc_maps.begin(); alpar@209: it != _arc_maps.end(); ++it) { deba@127: if (it->first == "label") { alpar@209: label = it->second; alpar@209: break; alpar@209: } deba@127: } deba@127: deba@127: *_os << "@arcs"; deba@127: if (!_arcs_caption.empty()) { alpar@209: _writer_bits::writeToken(*_os << ' ', _arcs_caption); deba@127: } deba@127: *_os << std::endl; deba@127: deba@127: *_os << '\t' << '\t'; deba@127: if (label == 0) { alpar@209: *_os << "label" << '\t'; deba@127: } deba@127: for (typename ArcMaps::iterator it = _arc_maps.begin(); alpar@209: it != _arc_maps.end(); ++it) { alpar@209: _writer_bits::writeToken(*_os, it->first) << '\t'; deba@127: } deba@127: *_os << std::endl; deba@127: deba@127: std::vector arcs; deba@127: for (ArcIt n(_digraph); n != INVALID; ++n) { alpar@209: arcs.push_back(n); deba@127: } alpar@209: deba@127: if (label == 0) { alpar@209: IdMap id_map(_digraph); alpar@209: _writer_bits::MapLess > id_less(id_map); alpar@209: std::sort(arcs.begin(), arcs.end(), id_less); deba@127: } else { alpar@209: label->sort(arcs); deba@127: } deba@127: deba@127: for (int i = 0; i < static_cast(arcs.size()); ++i) { alpar@209: Arc a = arcs[i]; alpar@209: _writer_bits::writeToken(*_os, _node_index. alpar@209: find(_digraph.source(a))->second); alpar@209: *_os << '\t'; alpar@209: _writer_bits::writeToken(*_os, _node_index. alpar@209: find(_digraph.target(a))->second); alpar@209: *_os << '\t'; alpar@209: if (label == 0) { alpar@209: std::ostringstream os; alpar@209: os << _digraph.id(a); alpar@209: _writer_bits::writeToken(*_os, os.str()); alpar@209: *_os << '\t'; alpar@209: _arc_index.insert(std::make_pair(a, os.str())); alpar@209: } alpar@209: for (typename ArcMaps::iterator it = _arc_maps.begin(); alpar@209: it != _arc_maps.end(); ++it) { alpar@209: std::string value = it->second->get(a); alpar@209: _writer_bits::writeToken(*_os, value); alpar@209: if (it->first == "label") { alpar@209: _arc_index.insert(std::make_pair(a, value)); alpar@209: } alpar@209: *_os << '\t'; alpar@209: } alpar@209: *_os << std::endl; deba@127: } deba@127: } deba@127: deba@185: void createArcIndex() { deba@185: _writer_bits::MapStorageBase* label = 0; deba@185: for (typename ArcMaps::iterator it = _arc_maps.begin(); alpar@209: it != _arc_maps.end(); ++it) { deba@185: if (it->first == "label") { alpar@209: label = it->second; alpar@209: break; alpar@209: } deba@185: } deba@185: deba@185: if (label == 0) { alpar@209: for (ArcIt a(_digraph); a != INVALID; ++a) { alpar@209: std::ostringstream os; alpar@209: os << _digraph.id(a); alpar@209: _arc_index.insert(std::make_pair(a, os.str())); alpar@209: } deba@185: } else { alpar@209: for (ArcIt a(_digraph); a != INVALID; ++a) { alpar@209: std::string value = label->get(a); alpar@209: _arc_index.insert(std::make_pair(a, value)); alpar@209: } deba@185: } deba@185: } deba@185: deba@127: void writeAttributes() { deba@127: if (_attributes.empty()) return; deba@127: *_os << "@attributes"; deba@127: if (!_attributes_caption.empty()) { alpar@209: _writer_bits::writeToken(*_os << ' ', _attributes_caption); deba@127: } deba@127: *_os << std::endl; deba@127: for (typename Attributes::iterator it = _attributes.begin(); alpar@209: it != _attributes.end(); ++it) { alpar@209: _writer_bits::writeToken(*_os, it->first) << ' '; alpar@209: _writer_bits::writeToken(*_os, it->second->get()); alpar@209: *_os << std::endl; deba@127: } deba@127: } alpar@209: deba@127: public: alpar@209: alpar@209: /// \name Execution of the writer alpar@156: /// @{ alpar@156: alpar@156: /// \brief Start the batch processing alpar@156: /// kpeter@192: /// This function starts the batch processing. deba@127: void run() { deba@127: if (!_skip_nodes) { alpar@209: writeNodes(); deba@185: } else { alpar@209: createNodeIndex(); deba@127: } alpar@209: if (!_skip_arcs) { alpar@209: writeArcs(); deba@185: } else { alpar@209: createArcIndex(); deba@127: } deba@127: writeAttributes(); deba@127: } deba@127: kpeter@192: /// \brief Give back the stream of the writer alpar@156: /// kpeter@192: /// Give back the stream of the writer. alpar@156: std::ostream& ostream() { deba@127: return *_os; deba@127: } alpar@156: alpar@156: /// @} deba@127: }; deba@127: kpeter@487: /// \brief Return a \ref DigraphWriter class kpeter@487: /// kpeter@487: /// This function just returns a \ref DigraphWriter class. kpeter@487: /// \relates DigraphWriter kpeter@487: template kpeter@487: DigraphWriter digraphWriter(const Digraph& digraph, kpeter@487: std::ostream& os) { kpeter@487: DigraphWriter tmp(digraph, os); kpeter@487: return tmp; kpeter@487: } kpeter@487: kpeter@487: /// \brief Return a \ref DigraphWriter class kpeter@487: /// kpeter@487: /// This function just returns a \ref DigraphWriter class. kpeter@487: /// \relates DigraphWriter kpeter@487: template kpeter@487: DigraphWriter digraphWriter(const Digraph& digraph, kpeter@487: const std::string& fn) { kpeter@487: DigraphWriter tmp(digraph, fn); kpeter@487: return tmp; kpeter@487: } kpeter@487: kpeter@487: /// \brief Return a \ref DigraphWriter class kpeter@487: /// kpeter@487: /// This function just returns a \ref DigraphWriter class. kpeter@487: /// \relates DigraphWriter kpeter@487: template kpeter@487: DigraphWriter digraphWriter(const Digraph& digraph, kpeter@487: const char* fn) { kpeter@487: DigraphWriter tmp(digraph, fn); kpeter@487: return tmp; kpeter@487: } kpeter@487: ladanyi@303: template ladanyi@303: class GraphWriter; ladanyi@303: ladanyi@303: template ladanyi@303: GraphWriter graphWriter(const Graph& graph, kpeter@487: std::ostream& os = std::cout); ladanyi@303: template kpeter@487: GraphWriter graphWriter(const Graph& graph, const std::string& fn); ladanyi@303: template kpeter@487: GraphWriter graphWriter(const Graph& graph, const char* fn); deba@165: deba@165: /// \ingroup lemon_io alpar@209: /// kpeter@192: /// \brief \ref lgf-format "LGF" writer for directed graphs deba@165: /// deba@165: /// This utility writes an \ref lgf-format "LGF" file. kpeter@192: /// kpeter@192: /// It can be used almost the same way as \c DigraphWriter. kpeter@192: /// The only difference is that this class can handle edges and kpeter@192: /// edge maps as well as arcs and arc maps. deba@201: /// deba@201: /// The arc maps are written into the file as two columns, the deba@201: /// caption of the columns are the name of the map prefixed with \c deba@201: /// '+' and \c '-'. The arcs are written into the \c \@attributes deba@201: /// section as a \c '+' or a \c '-' prefix (depends on the direction deba@201: /// of the arc) and the label of corresponding edge. kpeter@559: template deba@165: class GraphWriter { deba@165: public: deba@165: kpeter@559: typedef GR Graph; deba@165: TEMPLATE_GRAPH_TYPEDEFS(Graph); alpar@209: deba@165: private: deba@165: deba@165: deba@165: std::ostream* _os; deba@165: bool local_os; deba@165: deba@237: const Graph& _graph; deba@165: deba@165: std::string _nodes_caption; deba@165: std::string _edges_caption; deba@165: std::string _attributes_caption; alpar@209: deba@165: typedef std::map NodeIndex; deba@165: NodeIndex _node_index; deba@165: typedef std::map EdgeIndex; deba@165: EdgeIndex _edge_index; deba@165: alpar@209: typedef std::vector* > > NodeMaps; alpar@209: NodeMaps _node_maps; deba@165: alpar@209: typedef std::vector* > >EdgeMaps; deba@165: EdgeMaps _edge_maps; deba@165: alpar@209: typedef std::vector > Attributes; deba@165: Attributes _attributes; deba@165: deba@165: bool _skip_nodes; deba@165: bool _skip_edges; deba@165: deba@165: public: deba@165: deba@165: /// \brief Constructor deba@165: /// deba@165: /// Construct a directed graph writer, which writes to the given deba@165: /// output stream. kpeter@293: GraphWriter(const Graph& graph, std::ostream& os = std::cout) kpeter@293: : _os(&os), local_os(false), _graph(graph), alpar@209: _skip_nodes(false), _skip_edges(false) {} deba@165: deba@165: /// \brief Constructor deba@165: /// deba@165: /// Construct a directed graph writer, which writes to the given deba@165: /// output file. kpeter@293: GraphWriter(const Graph& graph, const std::string& fn) deba@165: : _os(new std::ofstream(fn.c_str())), local_os(true), _graph(graph), deba@290: _skip_nodes(false), _skip_edges(false) { deba@295: if (!(*_os)) { deba@295: delete _os; deba@295: throw IoError("Cannot write file", fn); deba@295: } deba@290: } deba@165: deba@165: /// \brief Constructor deba@165: /// deba@165: /// Construct a directed graph writer, which writes to the given deba@165: /// output file. kpeter@293: GraphWriter(const Graph& graph, const char* fn) deba@165: : _os(new std::ofstream(fn)), local_os(true), _graph(graph), deba@290: _skip_nodes(false), _skip_edges(false) { deba@295: if (!(*_os)) { deba@295: delete _os; deba@295: throw IoError("Cannot write file", fn); deba@295: } deba@290: } deba@165: deba@165: /// \brief Destructor deba@165: ~GraphWriter() { alpar@209: for (typename NodeMaps::iterator it = _node_maps.begin(); alpar@209: it != _node_maps.end(); ++it) { alpar@209: delete it->second; deba@165: } deba@165: alpar@209: for (typename EdgeMaps::iterator it = _edge_maps.begin(); alpar@209: it != _edge_maps.end(); ++it) { alpar@209: delete it->second; deba@165: } deba@165: alpar@209: for (typename Attributes::iterator it = _attributes.begin(); alpar@209: it != _attributes.end(); ++it) { alpar@209: delete it->second; deba@165: } deba@165: deba@165: if (local_os) { alpar@209: delete _os; deba@165: } deba@165: } alpar@209: deba@190: private: deba@165: kpeter@559: template kpeter@559: friend GraphWriter graphWriter(const Graph& graph, kpeter@559: std::ostream& os); kpeter@559: template kpeter@559: friend GraphWriter graphWriter(const Graph& graph, kpeter@559: const std::string& fn); kpeter@559: template kpeter@559: friend GraphWriter graphWriter(const Graph& graph, kpeter@559: const char *fn); kpeter@487: alpar@209: GraphWriter(GraphWriter& other) deba@190: : _os(other._os), local_os(other.local_os), _graph(other._graph), alpar@209: _skip_nodes(other._skip_nodes), _skip_edges(other._skip_edges) { deba@190: deba@190: other._os = 0; deba@190: other.local_os = false; deba@190: deba@190: _node_index.swap(other._node_index); deba@190: _edge_index.swap(other._edge_index); deba@190: deba@190: _node_maps.swap(other._node_maps); deba@190: _edge_maps.swap(other._edge_maps); deba@190: _attributes.swap(other._attributes); deba@190: deba@190: _nodes_caption = other._nodes_caption; deba@190: _edges_caption = other._edges_caption; deba@190: _attributes_caption = other._attributes_caption; deba@190: } deba@190: deba@165: GraphWriter& operator=(const GraphWriter&); deba@165: deba@165: public: deba@165: deba@165: /// \name Writing rules deba@165: /// @{ alpar@209: kpeter@192: /// \brief Node map writing rule deba@165: /// kpeter@192: /// Add a node map writing rule to the writer. deba@165: template deba@165: GraphWriter& nodeMap(const std::string& caption, const Map& map) { deba@165: checkConcept, Map>(); alpar@209: _writer_bits::MapStorageBase* storage = alpar@209: new _writer_bits::MapStorage(map); deba@165: _node_maps.push_back(std::make_pair(caption, storage)); deba@165: return *this; deba@165: } deba@165: deba@165: /// \brief Node map writing rule deba@165: /// deba@165: /// Add a node map writing rule with specialized converter to the deba@165: /// writer. deba@165: template alpar@209: GraphWriter& nodeMap(const std::string& caption, const Map& map, alpar@209: const Converter& converter = Converter()) { deba@165: checkConcept, Map>(); alpar@209: _writer_bits::MapStorageBase* storage = alpar@209: new _writer_bits::MapStorage(map, converter); deba@165: _node_maps.push_back(std::make_pair(caption, storage)); deba@165: return *this; deba@165: } deba@165: deba@165: /// \brief Edge map writing rule deba@165: /// deba@165: /// Add an edge map writing rule to the writer. deba@165: template deba@165: GraphWriter& edgeMap(const std::string& caption, const Map& map) { deba@165: checkConcept, Map>(); alpar@209: _writer_bits::MapStorageBase* storage = alpar@209: new _writer_bits::MapStorage(map); deba@165: _edge_maps.push_back(std::make_pair(caption, storage)); deba@165: return *this; deba@165: } deba@165: deba@165: /// \brief Edge map writing rule deba@165: /// deba@165: /// Add an edge map writing rule with specialized converter to the deba@165: /// writer. deba@165: template alpar@209: GraphWriter& edgeMap(const std::string& caption, const Map& map, alpar@209: const Converter& converter = Converter()) { deba@165: checkConcept, Map>(); alpar@209: _writer_bits::MapStorageBase* storage = alpar@209: new _writer_bits::MapStorage(map, converter); deba@165: _edge_maps.push_back(std::make_pair(caption, storage)); deba@165: return *this; deba@165: } deba@165: deba@165: /// \brief Arc map writing rule deba@165: /// deba@165: /// Add an arc map writing rule to the writer. deba@165: template deba@165: GraphWriter& arcMap(const std::string& caption, const Map& map) { deba@165: checkConcept, Map>(); alpar@209: _writer_bits::MapStorageBase* forward_storage = alpar@209: new _writer_bits::GraphArcMapStorage(_graph, map); deba@165: _edge_maps.push_back(std::make_pair('+' + caption, forward_storage)); alpar@209: _writer_bits::MapStorageBase* backward_storage = alpar@209: new _writer_bits::GraphArcMapStorage(_graph, map); deba@165: _edge_maps.push_back(std::make_pair('-' + caption, backward_storage)); deba@165: return *this; deba@165: } deba@165: deba@165: /// \brief Arc map writing rule deba@165: /// deba@165: /// Add an arc map writing rule with specialized converter to the deba@165: /// writer. deba@165: template alpar@209: GraphWriter& arcMap(const std::string& caption, const Map& map, alpar@209: const Converter& converter = Converter()) { deba@165: checkConcept, Map>(); alpar@209: _writer_bits::MapStorageBase* forward_storage = alpar@209: new _writer_bits::GraphArcMapStorage alpar@209: (_graph, map, converter); deba@165: _edge_maps.push_back(std::make_pair('+' + caption, forward_storage)); alpar@209: _writer_bits::MapStorageBase* backward_storage = alpar@209: new _writer_bits::GraphArcMapStorage alpar@209: (_graph, map, converter); deba@165: _edge_maps.push_back(std::make_pair('-' + caption, backward_storage)); deba@165: return *this; deba@165: } deba@165: deba@165: /// \brief Attribute writing rule deba@165: /// deba@165: /// Add an attribute writing rule to the writer. deba@165: template deba@165: GraphWriter& attribute(const std::string& caption, const Value& value) { alpar@209: _writer_bits::ValueStorageBase* storage = alpar@209: new _writer_bits::ValueStorage(value); deba@165: _attributes.push_back(std::make_pair(caption, storage)); deba@165: return *this; deba@165: } deba@165: deba@165: /// \brief Attribute writing rule deba@165: /// deba@165: /// Add an attribute writing rule with specialized converter to the deba@165: /// writer. deba@165: template alpar@209: GraphWriter& attribute(const std::string& caption, const Value& value, alpar@209: const Converter& converter = Converter()) { alpar@209: _writer_bits::ValueStorageBase* storage = alpar@209: new _writer_bits::ValueStorage(value, converter); deba@165: _attributes.push_back(std::make_pair(caption, storage)); deba@165: return *this; deba@165: } deba@165: deba@165: /// \brief Node writing rule deba@165: /// deba@165: /// Add a node writing rule to the writer. deba@165: GraphWriter& node(const std::string& caption, const Node& node) { deba@165: typedef _writer_bits::MapLookUpConverter Converter; deba@165: Converter converter(_node_index); alpar@209: _writer_bits::ValueStorageBase* storage = alpar@209: new _writer_bits::ValueStorage(node, converter); deba@165: _attributes.push_back(std::make_pair(caption, storage)); deba@165: return *this; deba@165: } deba@165: deba@165: /// \brief Edge writing rule deba@165: /// deba@165: /// Add an edge writing rule to writer. deba@165: GraphWriter& edge(const std::string& caption, const Edge& edge) { deba@165: typedef _writer_bits::MapLookUpConverter Converter; deba@165: Converter converter(_edge_index); alpar@209: _writer_bits::ValueStorageBase* storage = alpar@209: new _writer_bits::ValueStorage(edge, converter); deba@165: _attributes.push_back(std::make_pair(caption, storage)); deba@165: return *this; deba@165: } deba@165: deba@165: /// \brief Arc writing rule deba@165: /// deba@165: /// Add an arc writing rule to writer. deba@165: GraphWriter& arc(const std::string& caption, const Arc& arc) { deba@165: typedef _writer_bits::GraphArcLookUpConverter Converter; deba@165: Converter converter(_graph, _edge_index); alpar@209: _writer_bits::ValueStorageBase* storage = alpar@209: new _writer_bits::ValueStorage(arc, converter); deba@165: _attributes.push_back(std::make_pair(caption, storage)); deba@165: return *this; deba@165: } deba@165: kpeter@192: /// \name Section captions deba@165: /// @{ deba@165: kpeter@192: /// \brief Add an additional caption to the \c \@nodes section deba@165: /// kpeter@192: /// Add an additional caption to the \c \@nodes section. deba@165: GraphWriter& nodes(const std::string& caption) { deba@165: _nodes_caption = caption; deba@165: return *this; deba@165: } deba@165: kpeter@192: /// \brief Add an additional caption to the \c \@arcs section deba@165: /// kpeter@192: /// Add an additional caption to the \c \@arcs section. deba@165: GraphWriter& edges(const std::string& caption) { deba@165: _edges_caption = caption; deba@165: return *this; deba@165: } deba@165: kpeter@192: /// \brief Add an additional caption to the \c \@attributes section deba@165: /// kpeter@192: /// Add an additional caption to the \c \@attributes section. deba@165: GraphWriter& attributes(const std::string& caption) { deba@165: _attributes_caption = caption; deba@165: return *this; deba@165: } deba@165: deba@165: /// \name Skipping section deba@165: /// @{ deba@165: deba@165: /// \brief Skip writing the node set deba@165: /// kpeter@192: /// The \c \@nodes section will not be written to the stream. deba@165: GraphWriter& skipNodes() { deba@165: LEMON_ASSERT(!_skip_nodes, "Multiple usage of skipNodes() member"); deba@185: _skip_nodes = true; deba@165: return *this; deba@165: } deba@165: deba@165: /// \brief Skip writing edge set deba@165: /// kpeter@192: /// The \c \@edges section will not be written to the stream. deba@165: GraphWriter& skipEdges() { deba@165: LEMON_ASSERT(!_skip_edges, "Multiple usage of skipEdges() member"); deba@185: _skip_edges = true; deba@165: return *this; deba@165: } deba@165: deba@165: /// @} deba@165: deba@165: private: deba@165: deba@165: void writeNodes() { deba@165: _writer_bits::MapStorageBase* label = 0; deba@165: for (typename NodeMaps::iterator it = _node_maps.begin(); alpar@209: it != _node_maps.end(); ++it) { deba@165: if (it->first == "label") { alpar@209: label = it->second; alpar@209: break; alpar@209: } deba@165: } deba@165: deba@165: *_os << "@nodes"; deba@165: if (!_nodes_caption.empty()) { alpar@209: _writer_bits::writeToken(*_os << ' ', _nodes_caption); deba@165: } deba@165: *_os << std::endl; deba@165: deba@165: if (label == 0) { alpar@209: *_os << "label" << '\t'; deba@165: } deba@165: for (typename NodeMaps::iterator it = _node_maps.begin(); alpar@209: it != _node_maps.end(); ++it) { alpar@209: _writer_bits::writeToken(*_os, it->first) << '\t'; deba@165: } deba@165: *_os << std::endl; deba@165: deba@165: std::vector nodes; deba@165: for (NodeIt n(_graph); n != INVALID; ++n) { alpar@209: nodes.push_back(n); deba@165: } alpar@209: deba@165: if (label == 0) { alpar@209: IdMap id_map(_graph); alpar@209: _writer_bits::MapLess > id_less(id_map); alpar@209: std::sort(nodes.begin(), nodes.end(), id_less); deba@165: } else { alpar@209: label->sort(nodes); deba@165: } deba@165: deba@165: for (int i = 0; i < static_cast(nodes.size()); ++i) { alpar@209: Node n = nodes[i]; alpar@209: if (label == 0) { alpar@209: std::ostringstream os; alpar@209: os << _graph.id(n); alpar@209: _writer_bits::writeToken(*_os, os.str()); alpar@209: *_os << '\t'; alpar@209: _node_index.insert(std::make_pair(n, os.str())); alpar@209: } alpar@209: for (typename NodeMaps::iterator it = _node_maps.begin(); alpar@209: it != _node_maps.end(); ++it) { alpar@209: std::string value = it->second->get(n); alpar@209: _writer_bits::writeToken(*_os, value); alpar@209: if (it->first == "label") { alpar@209: _node_index.insert(std::make_pair(n, value)); alpar@209: } alpar@209: *_os << '\t'; alpar@209: } alpar@209: *_os << std::endl; deba@165: } deba@165: } deba@165: deba@185: void createNodeIndex() { deba@185: _writer_bits::MapStorageBase* label = 0; deba@185: for (typename NodeMaps::iterator it = _node_maps.begin(); alpar@209: it != _node_maps.end(); ++it) { deba@185: if (it->first == "label") { alpar@209: label = it->second; alpar@209: break; alpar@209: } deba@185: } deba@185: deba@185: if (label == 0) { alpar@209: for (NodeIt n(_graph); n != INVALID; ++n) { alpar@209: std::ostringstream os; alpar@209: os << _graph.id(n); alpar@209: _node_index.insert(std::make_pair(n, os.str())); alpar@209: } deba@185: } else { alpar@209: for (NodeIt n(_graph); n != INVALID; ++n) { alpar@209: std::string value = label->get(n); alpar@209: _node_index.insert(std::make_pair(n, value)); alpar@209: } deba@185: } deba@185: } deba@185: deba@165: void writeEdges() { deba@165: _writer_bits::MapStorageBase* label = 0; deba@165: for (typename EdgeMaps::iterator it = _edge_maps.begin(); alpar@209: it != _edge_maps.end(); ++it) { deba@165: if (it->first == "label") { alpar@209: label = it->second; alpar@209: break; alpar@209: } deba@165: } deba@165: deba@165: *_os << "@edges"; deba@165: if (!_edges_caption.empty()) { alpar@209: _writer_bits::writeToken(*_os << ' ', _edges_caption); deba@165: } deba@165: *_os << std::endl; deba@165: deba@165: *_os << '\t' << '\t'; deba@165: if (label == 0) { alpar@209: *_os << "label" << '\t'; deba@165: } deba@165: for (typename EdgeMaps::iterator it = _edge_maps.begin(); alpar@209: it != _edge_maps.end(); ++it) { alpar@209: _writer_bits::writeToken(*_os, it->first) << '\t'; deba@165: } deba@165: *_os << std::endl; deba@165: deba@165: std::vector edges; deba@165: for (EdgeIt n(_graph); n != INVALID; ++n) { alpar@209: edges.push_back(n); deba@165: } alpar@209: deba@165: if (label == 0) { alpar@209: IdMap id_map(_graph); alpar@209: _writer_bits::MapLess > id_less(id_map); alpar@209: std::sort(edges.begin(), edges.end(), id_less); deba@165: } else { alpar@209: label->sort(edges); deba@165: } deba@165: deba@165: for (int i = 0; i < static_cast(edges.size()); ++i) { alpar@209: Edge e = edges[i]; alpar@209: _writer_bits::writeToken(*_os, _node_index. alpar@209: find(_graph.u(e))->second); alpar@209: *_os << '\t'; alpar@209: _writer_bits::writeToken(*_os, _node_index. alpar@209: find(_graph.v(e))->second); alpar@209: *_os << '\t'; alpar@209: if (label == 0) { alpar@209: std::ostringstream os; alpar@209: os << _graph.id(e); alpar@209: _writer_bits::writeToken(*_os, os.str()); alpar@209: *_os << '\t'; alpar@209: _edge_index.insert(std::make_pair(e, os.str())); alpar@209: } alpar@209: for (typename EdgeMaps::iterator it = _edge_maps.begin(); alpar@209: it != _edge_maps.end(); ++it) { alpar@209: std::string value = it->second->get(e); alpar@209: _writer_bits::writeToken(*_os, value); alpar@209: if (it->first == "label") { alpar@209: _edge_index.insert(std::make_pair(e, value)); alpar@209: } alpar@209: *_os << '\t'; alpar@209: } alpar@209: *_os << std::endl; deba@165: } deba@165: } deba@165: deba@185: void createEdgeIndex() { deba@185: _writer_bits::MapStorageBase* label = 0; deba@185: for (typename EdgeMaps::iterator it = _edge_maps.begin(); alpar@209: it != _edge_maps.end(); ++it) { deba@185: if (it->first == "label") { alpar@209: label = it->second; alpar@209: break; alpar@209: } deba@185: } deba@185: deba@185: if (label == 0) { alpar@209: for (EdgeIt e(_graph); e != INVALID; ++e) { alpar@209: std::ostringstream os; alpar@209: os << _graph.id(e); alpar@209: _edge_index.insert(std::make_pair(e, os.str())); alpar@209: } deba@185: } else { alpar@209: for (EdgeIt e(_graph); e != INVALID; ++e) { alpar@209: std::string value = label->get(e); alpar@209: _edge_index.insert(std::make_pair(e, value)); alpar@209: } deba@185: } deba@185: } deba@185: deba@165: void writeAttributes() { deba@165: if (_attributes.empty()) return; deba@165: *_os << "@attributes"; deba@165: if (!_attributes_caption.empty()) { alpar@209: _writer_bits::writeToken(*_os << ' ', _attributes_caption); deba@165: } deba@165: *_os << std::endl; deba@165: for (typename Attributes::iterator it = _attributes.begin(); alpar@209: it != _attributes.end(); ++it) { alpar@209: _writer_bits::writeToken(*_os, it->first) << ' '; alpar@209: _writer_bits::writeToken(*_os, it->second->get()); alpar@209: *_os << std::endl; deba@165: } deba@165: } alpar@209: deba@165: public: alpar@209: alpar@209: /// \name Execution of the writer deba@165: /// @{ deba@165: deba@165: /// \brief Start the batch processing deba@165: /// kpeter@192: /// This function starts the batch processing. deba@165: void run() { deba@165: if (!_skip_nodes) { alpar@209: writeNodes(); deba@185: } else { alpar@209: createNodeIndex(); deba@165: } alpar@209: if (!_skip_edges) { alpar@209: writeEdges(); deba@185: } else { alpar@209: createEdgeIndex(); deba@165: } deba@165: writeAttributes(); deba@165: } deba@165: kpeter@192: /// \brief Give back the stream of the writer deba@165: /// kpeter@192: /// Give back the stream of the writer deba@165: std::ostream& ostream() { deba@165: return *_os; deba@165: } deba@165: deba@165: /// @} deba@165: }; deba@165: kpeter@487: /// \brief Return a \ref GraphWriter class kpeter@487: /// kpeter@487: /// This function just returns a \ref GraphWriter class. kpeter@487: /// \relates GraphWriter kpeter@487: template kpeter@487: GraphWriter graphWriter(const Graph& graph, kpeter@487: std::ostream& os) { kpeter@487: GraphWriter tmp(graph, os); kpeter@487: return tmp; kpeter@487: } kpeter@487: kpeter@487: /// \brief Return a \ref GraphWriter class kpeter@487: /// kpeter@487: /// This function just returns a \ref GraphWriter class. kpeter@487: /// \relates GraphWriter kpeter@487: template kpeter@487: GraphWriter graphWriter(const Graph& graph, const std::string& fn) { kpeter@487: GraphWriter tmp(graph, fn); kpeter@487: return tmp; kpeter@487: } kpeter@487: kpeter@487: /// \brief Return a \ref GraphWriter class kpeter@487: /// kpeter@487: /// This function just returns a \ref GraphWriter class. kpeter@487: /// \relates GraphWriter kpeter@487: template kpeter@487: GraphWriter graphWriter(const Graph& graph, const char* fn) { kpeter@487: GraphWriter tmp(graph, fn); kpeter@487: return tmp; kpeter@487: } kpeter@487: deba@248: class SectionWriter; deba@248: deba@248: SectionWriter sectionWriter(std::istream& is); deba@248: SectionWriter sectionWriter(const std::string& fn); deba@248: SectionWriter sectionWriter(const char* fn); deba@248: deba@248: /// \ingroup lemon_io deba@248: /// deba@248: /// \brief Section writer class deba@248: /// deba@248: /// In the \ref lgf-format "LGF" file extra sections can be placed, deba@248: /// which contain any data in arbitrary format. Such sections can be deba@248: /// written with this class. A writing rule can be added to the deba@248: /// class with two different functions. With the \c sectionLines() deba@248: /// function a generator can write the section line-by-line, while deba@248: /// with the \c sectionStream() member the section can be written to deba@248: /// an output stream. deba@248: class SectionWriter { deba@248: private: deba@248: deba@248: std::ostream* _os; deba@248: bool local_os; deba@248: deba@248: typedef std::vector > deba@248: Sections; deba@248: deba@248: Sections _sections; deba@248: deba@248: public: deba@248: deba@248: /// \brief Constructor deba@248: /// deba@248: /// Construct a section writer, which writes to the given output deba@248: /// stream. deba@248: SectionWriter(std::ostream& os) deba@248: : _os(&os), local_os(false) {} deba@248: deba@248: /// \brief Constructor deba@248: /// deba@248: /// Construct a section writer, which writes into the given file. deba@248: SectionWriter(const std::string& fn) deba@290: : _os(new std::ofstream(fn.c_str())), local_os(true) { deba@295: if (!(*_os)) { deba@295: delete _os; deba@295: throw IoError("Cannot write file", fn); deba@295: } deba@290: } deba@248: deba@248: /// \brief Constructor deba@248: /// deba@248: /// Construct a section writer, which writes into the given file. deba@248: SectionWriter(const char* fn) deba@290: : _os(new std::ofstream(fn)), local_os(true) { deba@295: if (!(*_os)) { deba@295: delete _os; deba@295: throw IoError("Cannot write file", fn); deba@295: } deba@290: } deba@248: deba@248: /// \brief Destructor deba@248: ~SectionWriter() { deba@248: for (Sections::iterator it = _sections.begin(); deba@248: it != _sections.end(); ++it) { deba@248: delete it->second; deba@248: } deba@248: deba@248: if (local_os) { deba@248: delete _os; deba@248: } deba@248: deba@248: } deba@248: deba@248: private: deba@248: deba@248: friend SectionWriter sectionWriter(std::ostream& os); deba@248: friend SectionWriter sectionWriter(const std::string& fn); deba@248: friend SectionWriter sectionWriter(const char* fn); deba@248: deba@248: SectionWriter(SectionWriter& other) deba@248: : _os(other._os), local_os(other.local_os) { deba@248: deba@248: other._os = 0; deba@248: other.local_os = false; deba@248: deba@248: _sections.swap(other._sections); deba@248: } deba@248: deba@248: SectionWriter& operator=(const SectionWriter&); deba@248: deba@248: public: deba@248: deba@248: /// \name Section writers deba@248: /// @{ deba@248: deba@248: /// \brief Add a section writer with line oriented writing deba@248: /// deba@248: /// The first parameter is the type descriptor of the section, the deba@248: /// second is a generator with std::string values. At the writing deba@248: /// process, the returned \c std::string will be written into the deba@248: /// output file until it is an empty string. deba@248: /// deba@248: /// For example, an integer vector is written into a section. deba@248: ///\code deba@248: /// @numbers deba@248: /// 12 45 23 78 deba@248: /// 4 28 38 28 deba@248: /// 23 6 16 deba@248: ///\endcode deba@248: /// deba@248: /// The generator is implemented as a struct. deba@248: ///\code deba@248: /// struct NumberSection { deba@248: /// std::vector::const_iterator _it, _end; deba@248: /// NumberSection(const std::vector& data) deba@248: /// : _it(data.begin()), _end(data.end()) {} deba@248: /// std::string operator()() { deba@248: /// int rem_in_line = 4; deba@248: /// std::ostringstream ls; deba@248: /// while (rem_in_line > 0 && _it != _end) { deba@248: /// ls << *(_it++) << ' '; deba@248: /// --rem_in_line; deba@248: /// } deba@248: /// return ls.str(); deba@248: /// } deba@248: /// }; deba@248: /// deba@248: /// // ... deba@248: /// deba@248: /// writer.sectionLines("numbers", NumberSection(vec)); deba@248: ///\endcode deba@248: template deba@248: SectionWriter& sectionLines(const std::string& type, Functor functor) { deba@248: LEMON_ASSERT(!type.empty(), "Type is empty."); deba@248: _sections.push_back(std::make_pair(type, deba@248: new _writer_bits::LineSection(functor))); deba@248: return *this; deba@248: } deba@248: deba@248: deba@248: /// \brief Add a section writer with stream oriented writing deba@248: /// deba@248: /// The first parameter is the type of the section, the second is deba@248: /// a functor, which takes a \c std::ostream& parameter. The deba@248: /// functor writes the section to the output stream. deba@248: /// \warning The last line must be closed with end-line character. deba@248: template deba@248: SectionWriter& sectionStream(const std::string& type, Functor functor) { deba@248: LEMON_ASSERT(!type.empty(), "Type is empty."); deba@248: _sections.push_back(std::make_pair(type, deba@248: new _writer_bits::StreamSection(functor))); deba@248: return *this; deba@248: } deba@248: deba@248: /// @} deba@248: deba@248: public: deba@248: deba@248: deba@248: /// \name Execution of the writer deba@248: /// @{ deba@248: deba@248: /// \brief Start the batch processing deba@248: /// deba@248: /// This function starts the batch processing. deba@248: void run() { deba@248: deba@248: LEMON_ASSERT(_os != 0, "This writer is assigned to an other writer"); deba@248: deba@248: for (Sections::iterator it = _sections.begin(); deba@248: it != _sections.end(); ++it) { deba@248: (*_os) << '@' << it->first << std::endl; deba@248: it->second->process(*_os); deba@248: } deba@248: } deba@248: deba@248: /// \brief Give back the stream of the writer deba@248: /// deba@248: /// Returns the stream of the writer deba@248: std::ostream& ostream() { deba@248: return *_os; deba@248: } deba@248: deba@248: /// @} deba@248: deba@248: }; deba@248: deba@248: /// \brief Return a \ref SectionWriter class deba@248: /// deba@248: /// This function just returns a \ref SectionWriter class. deba@248: /// \relates SectionWriter deba@248: inline SectionWriter sectionWriter(std::ostream& os) { deba@248: SectionWriter tmp(os); deba@248: return tmp; deba@248: } deba@248: deba@248: /// \brief Return a \ref SectionWriter class deba@248: /// deba@248: /// This function just returns a \ref SectionWriter class. deba@248: /// \relates SectionWriter deba@248: inline SectionWriter sectionWriter(const std::string& fn) { deba@248: SectionWriter tmp(fn); deba@248: return tmp; deba@248: } deba@248: deba@248: /// \brief Return a \ref SectionWriter class deba@248: /// deba@248: /// This function just returns a \ref SectionWriter class. deba@248: /// \relates SectionWriter deba@248: inline SectionWriter sectionWriter(const char* fn) { deba@248: SectionWriter tmp(fn); deba@248: return tmp; deba@248: } deba@127: } deba@127: deba@127: #endif