1 /* -*- mode: C++; indent-tabs-mode: nil; -*-
 
     3  * This file is a part of LEMON, a generic C++ optimization library.
 
     5  * Copyright (C) 2003-2008
 
     6  * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
 
     7  * (Egervary Research Group on Combinatorial Optimization, EGRES).
 
     9  * Permission to use, modify and distribute this software is granted
 
    10  * provided that this copyright notice appears in all copies. For
 
    11  * precise terms see the accompanying LICENSE file.
 
    13  * This software is provided "AS IS" with no warranty of any kind,
 
    14  * express or implied, and with no claim as to its suitability for any
 
    21 ///\brief \ref lgf-format "LEMON Graph Format" writer.
 
    24 #ifndef LEMON_LGF_WRITER_H
 
    25 #define LEMON_LGF_WRITER_H
 
    36 #include <lemon/core.h>
 
    37 #include <lemon/maps.h>
 
    39 #include <lemon/concept_check.h>
 
    40 #include <lemon/concepts/maps.h>
 
    44   namespace _writer_bits {
 
    46     template <typename Value>
 
    47     struct DefaultConverter {
 
    48       std::string operator()(const Value& value) {
 
    49         std::ostringstream os;
 
    56     bool operator<(const T&, const T&) {
 
    57       throw FormatError("Label map is not comparable");
 
    60     template <typename _Map>
 
    64       typedef typename Map::Key Item;
 
    70       MapLess(const Map& map) : _map(map) {}
 
    72       bool operator()(const Item& left, const Item& right) {
 
    73         return _map[left] < _map[right];
 
    77     template <typename _Graph, bool _dir, typename _Map>
 
    78     class GraphArcMapLess {
 
    82       typedef typename Graph::Edge Item;
 
    89       GraphArcMapLess(const Graph& graph, const Map& map)
 
    90         : _graph(graph), _map(map) {}
 
    92       bool operator()(const Item& left, const Item& right) {
 
    93         return _map[_graph.direct(left, _dir)] <
 
    94           _map[_graph.direct(right, _dir)];
 
    98     template <typename _Item>
 
    99     class MapStorageBase {
 
   105       virtual ~MapStorageBase() {}
 
   107       virtual std::string get(const Item& item) = 0;
 
   108       virtual void sort(std::vector<Item>&) = 0;
 
   111     template <typename _Item, typename _Map,
 
   112               typename _Converter = DefaultConverter<typename _Map::Value> >
 
   113     class MapStorage : public MapStorageBase<_Item> {
 
   116       typedef _Converter Converter;
 
   121       Converter _converter;
 
   124       MapStorage(const Map& map, const Converter& converter = Converter())
 
   125         : _map(map), _converter(converter) {}
 
   126       virtual ~MapStorage() {}
 
   128       virtual std::string get(const Item& item) {
 
   129         return _converter(_map[item]);
 
   131       virtual void sort(std::vector<Item>& items) {
 
   132         MapLess<Map> less(_map);
 
   133         std::sort(items.begin(), items.end(), less);
 
   137     template <typename _Graph, bool _dir, typename _Map,
 
   138               typename _Converter = DefaultConverter<typename _Map::Value> >
 
   139     class GraphArcMapStorage : public MapStorageBase<typename _Graph::Edge> {
 
   142       typedef _Converter Converter;
 
   143       typedef _Graph Graph;
 
   144       typedef typename Graph::Edge Item;
 
   145       static const bool dir = _dir;
 
   150       Converter _converter;
 
   153       GraphArcMapStorage(const Graph& graph, const Map& map,
 
   154                          const Converter& converter = Converter())
 
   155         : _graph(graph), _map(map), _converter(converter) {}
 
   156       virtual ~GraphArcMapStorage() {}
 
   158       virtual std::string get(const Item& item) {
 
   159         return _converter(_map[_graph.direct(item, dir)]);
 
   161       virtual void sort(std::vector<Item>& items) {
 
   162         GraphArcMapLess<Graph, dir, Map> less(_graph, _map);
 
   163         std::sort(items.begin(), items.end(), less);
 
   167     class ValueStorageBase {
 
   169       ValueStorageBase() {}
 
   170       virtual ~ValueStorageBase() {}
 
   172       virtual std::string get() = 0;
 
   175     template <typename _Value, typename _Converter = DefaultConverter<_Value> >
 
   176     class ValueStorage : public ValueStorageBase {
 
   178       typedef _Value Value;
 
   179       typedef _Converter Converter;
 
   183       Converter _converter;
 
   186       ValueStorage(const Value& value, const Converter& converter = Converter())
 
   187         : _value(value), _converter(converter) {}
 
   189       virtual std::string get() {
 
   190         return _converter(_value);
 
   194     template <typename Value>
 
   195     struct MapLookUpConverter {
 
   196       const std::map<Value, std::string>& _map;
 
   198       MapLookUpConverter(const std::map<Value, std::string>& map)
 
   201       std::string operator()(const Value& str) {
 
   202         typename std::map<Value, std::string>::const_iterator it =
 
   204         if (it == _map.end()) {
 
   205           throw FormatError("Item not found");
 
   211     template <typename Graph>
 
   212     struct GraphArcLookUpConverter {
 
   214       const std::map<typename Graph::Edge, std::string>& _map;
 
   216       GraphArcLookUpConverter(const Graph& graph,
 
   217                               const std::map<typename Graph::Edge,
 
   219         : _graph(graph), _map(map) {}
 
   221       std::string operator()(const typename Graph::Arc& val) {
 
   222         typename std::map<typename Graph::Edge, std::string>
 
   223           ::const_iterator it = _map.find(val);
 
   224         if (it == _map.end()) {
 
   225           throw FormatError("Item not found");
 
   227         return (_graph.direction(val) ? '+' : '-') + it->second;
 
   231     inline bool isWhiteSpace(char c) {
 
   232       return c == ' ' || c == '\t' || c == '\v' ||
 
   233         c == '\n' || c == '\r' || c == '\f';
 
   236     inline bool isEscaped(char c) {
 
   237       return c == '\\' || c == '\"' || c == '\'' ||
 
   238         c == '\a' || c == '\b';
 
   241     inline static void writeEscape(std::ostream& os, char c) {
 
   272           std::ios::fmtflags flags = os.flags();
 
   273           os << '\\' << std::oct << static_cast<int>(c);
 
   282     inline bool requireEscape(const std::string& str) {
 
   283       if (str.empty() || str[0] == '@') return true;
 
   284       std::istringstream is(str);
 
   287         if (isWhiteSpace(c) || isEscaped(c)) {
 
   294     inline std::ostream& writeToken(std::ostream& os, const std::string& str) {
 
   296       if (requireEscape(str)) {
 
   298         for (std::string::const_iterator it = str.begin();
 
   299              it != str.end(); ++it) {
 
   300           writeEscape(os, *it);
 
   311       virtual ~Section() {}
 
   312       virtual void process(std::ostream& os) = 0;
 
   315     template <typename Functor>
 
   316     class LineSection : public Section {
 
   323       LineSection(const Functor& functor) : _functor(functor) {}
 
   324       virtual ~LineSection() {}
 
   326       virtual void process(std::ostream& os) {
 
   328         while (!(line = _functor()).empty()) os << line << std::endl;
 
   332     template <typename Functor>
 
   333     class StreamSection : public Section {
 
   340       StreamSection(const Functor& functor) : _functor(functor) {}
 
   341       virtual ~StreamSection() {}
 
   343       virtual void process(std::ostream& os) {
 
   350   template <typename Digraph>
 
   353   /// \brief Return a \ref DigraphWriter class
 
   355   /// This function just returns a \ref DigraphWriter class.
 
   356   /// \relates DigraphWriter
 
   357   template <typename Digraph>
 
   358   DigraphWriter<Digraph> digraphWriter(const Digraph& digraph,
 
   359                                        std::ostream& os = std::cout) {
 
   360     DigraphWriter<Digraph> tmp(digraph, os);
 
   364   /// \brief Return a \ref DigraphWriter class
 
   366   /// This function just returns a \ref DigraphWriter class.
 
   367   /// \relates DigraphWriter
 
   368   template <typename Digraph>
 
   369   DigraphWriter<Digraph> digraphWriter(const Digraph& digraph,
 
   370                                        const std::string& fn) {
 
   371     DigraphWriter<Digraph> tmp(digraph, fn);
 
   375   /// \brief Return a \ref DigraphWriter class
 
   377   /// This function just returns a \ref DigraphWriter class.
 
   378   /// \relates DigraphWriter
 
   379   template <typename Digraph>
 
   380   DigraphWriter<Digraph> digraphWriter(const Digraph& digraph,
 
   382     DigraphWriter<Digraph> tmp(digraph, fn);
 
   386   /// \ingroup lemon_io
 
   388   /// \brief \ref lgf-format "LGF" writer for directed graphs
 
   390   /// This utility writes an \ref lgf-format "LGF" file.
 
   392   /// The writing method does a batch processing. The user creates a
 
   393   /// writer object, then various writing rules can be added to the
 
   394   /// writer, and eventually the writing is executed with the \c run()
 
   395   /// member function. A map writing rule can be added to the writer
 
   396   /// with the \c nodeMap() or \c arcMap() members. An optional
 
   397   /// converter parameter can also be added as a standard functor
 
   398   /// converting from the value type of the map to \c std::string. If it
 
   399   /// is set, it will determine how the value type of the map is written to
 
   400   /// the output stream. If the functor is not set, then a default
 
   401   /// conversion will be used. The \c attribute(), \c node() and \c
 
   402   /// arc() functions are used to add attribute writing rules.
 
   405   /// DigraphWriter<Digraph>(digraph, std::cout).
 
   406   ///   nodeMap("coordinates", coord_map).
 
   407   ///   nodeMap("size", size).
 
   408   ///   nodeMap("title", title).
 
   409   ///   arcMap("capacity", cap_map).
 
   410   ///   node("source", src).
 
   411   ///   node("target", trg).
 
   412   ///   attribute("caption", caption).
 
   417   /// By default, the writer does not write additional captions to the
 
   418   /// sections, but they can be give as an optional parameter of
 
   419   /// the \c nodes(), \c arcs() or \c
 
   420   /// attributes() functions.
 
   422   /// The \c skipNodes() and \c skipArcs() functions forbid the
 
   423   /// writing of the sections. If two arc sections should be written
 
   424   /// to the output, it can be done in two passes, the first pass
 
   425   /// writes the node section and the first arc section, then the
 
   426   /// second pass skips the node section and writes just the arc
 
   427   /// section to the stream. The output stream can be retrieved with
 
   428   /// the \c ostream() function, hence the second pass can append its
 
   429   /// output to the output of the first pass.
 
   430   template <typename _Digraph>
 
   431   class DigraphWriter {
 
   434     typedef _Digraph Digraph;
 
   435     TEMPLATE_DIGRAPH_TYPEDEFS(Digraph);
 
   443     const Digraph& _digraph;
 
   445     std::string _nodes_caption;
 
   446     std::string _arcs_caption;
 
   447     std::string _attributes_caption;
 
   449     typedef std::map<Node, std::string> NodeIndex;
 
   450     NodeIndex _node_index;
 
   451     typedef std::map<Arc, std::string> ArcIndex;
 
   454     typedef std::vector<std::pair<std::string,
 
   455       _writer_bits::MapStorageBase<Node>* > > NodeMaps;
 
   458     typedef std::vector<std::pair<std::string,
 
   459       _writer_bits::MapStorageBase<Arc>* > >ArcMaps;
 
   462     typedef std::vector<std::pair<std::string,
 
   463       _writer_bits::ValueStorageBase*> > Attributes;
 
   464     Attributes _attributes;
 
   471     /// \brief Constructor
 
   473     /// Construct a directed graph writer, which writes to the given
 
   475     DigraphWriter(const Digraph& digraph, std::ostream& os = std::cout)
 
   476       : _os(&os), local_os(false), _digraph(digraph),
 
   477         _skip_nodes(false), _skip_arcs(false) {}
 
   479     /// \brief Constructor
 
   481     /// Construct a directed graph writer, which writes to the given
 
   483     DigraphWriter(const Digraph& digraph, const std::string& fn)
 
   484       : _os(new std::ofstream(fn.c_str())), local_os(true), _digraph(digraph),
 
   485         _skip_nodes(false), _skip_arcs(false) {
 
   488         throw IoError("Cannot write file", fn);
 
   492     /// \brief Constructor
 
   494     /// Construct a directed graph writer, which writes to the given
 
   496     DigraphWriter(const Digraph& digraph, const char* fn)
 
   497       : _os(new std::ofstream(fn)), local_os(true), _digraph(digraph),
 
   498         _skip_nodes(false), _skip_arcs(false) {
 
   501         throw IoError("Cannot write file", fn);
 
   505     /// \brief Destructor
 
   507       for (typename NodeMaps::iterator it = _node_maps.begin();
 
   508            it != _node_maps.end(); ++it) {
 
   512       for (typename ArcMaps::iterator it = _arc_maps.begin();
 
   513            it != _arc_maps.end(); ++it) {
 
   517       for (typename Attributes::iterator it = _attributes.begin();
 
   518            it != _attributes.end(); ++it) {
 
   529     friend DigraphWriter<Digraph> digraphWriter<>(const Digraph& digraph,
 
   531     friend DigraphWriter<Digraph> digraphWriter<>(const Digraph& digraph,
 
   532                                                   const std::string& fn);
 
   533     friend DigraphWriter<Digraph> digraphWriter<>(const Digraph& digraph,
 
   536     DigraphWriter(DigraphWriter& other)
 
   537       : _os(other._os), local_os(other.local_os), _digraph(other._digraph),
 
   538         _skip_nodes(other._skip_nodes), _skip_arcs(other._skip_arcs) {
 
   541       other.local_os = false;
 
   543       _node_index.swap(other._node_index);
 
   544       _arc_index.swap(other._arc_index);
 
   546       _node_maps.swap(other._node_maps);
 
   547       _arc_maps.swap(other._arc_maps);
 
   548       _attributes.swap(other._attributes);
 
   550       _nodes_caption = other._nodes_caption;
 
   551       _arcs_caption = other._arcs_caption;
 
   552       _attributes_caption = other._attributes_caption;
 
   555     DigraphWriter& operator=(const DigraphWriter&);
 
   559     /// \name Writing rules
 
   562     /// \brief Node map writing rule
 
   564     /// Add a node map writing rule to the writer.
 
   565     template <typename Map>
 
   566     DigraphWriter& nodeMap(const std::string& caption, const Map& map) {
 
   567       checkConcept<concepts::ReadMap<Node, typename Map::Value>, Map>();
 
   568       _writer_bits::MapStorageBase<Node>* storage =
 
   569         new _writer_bits::MapStorage<Node, Map>(map);
 
   570       _node_maps.push_back(std::make_pair(caption, storage));
 
   574     /// \brief Node map writing rule
 
   576     /// Add a node map writing rule with specialized converter to the
 
   578     template <typename Map, typename Converter>
 
   579     DigraphWriter& nodeMap(const std::string& caption, const Map& map,
 
   580                            const Converter& converter = Converter()) {
 
   581       checkConcept<concepts::ReadMap<Node, typename Map::Value>, Map>();
 
   582       _writer_bits::MapStorageBase<Node>* storage =
 
   583         new _writer_bits::MapStorage<Node, Map, Converter>(map, converter);
 
   584       _node_maps.push_back(std::make_pair(caption, storage));
 
   588     /// \brief Arc map writing rule
 
   590     /// Add an arc map writing rule to the writer.
 
   591     template <typename Map>
 
   592     DigraphWriter& arcMap(const std::string& caption, const Map& map) {
 
   593       checkConcept<concepts::ReadMap<Arc, typename Map::Value>, Map>();
 
   594       _writer_bits::MapStorageBase<Arc>* storage =
 
   595         new _writer_bits::MapStorage<Arc, Map>(map);
 
   596       _arc_maps.push_back(std::make_pair(caption, storage));
 
   600     /// \brief Arc map writing rule
 
   602     /// Add an arc map writing rule with specialized converter to the
 
   604     template <typename Map, typename Converter>
 
   605     DigraphWriter& arcMap(const std::string& caption, const Map& map,
 
   606                           const Converter& converter = Converter()) {
 
   607       checkConcept<concepts::ReadMap<Arc, typename Map::Value>, Map>();
 
   608       _writer_bits::MapStorageBase<Arc>* storage =
 
   609         new _writer_bits::MapStorage<Arc, Map, Converter>(map, converter);
 
   610       _arc_maps.push_back(std::make_pair(caption, storage));
 
   614     /// \brief Attribute writing rule
 
   616     /// Add an attribute writing rule to the writer.
 
   617     template <typename Value>
 
   618     DigraphWriter& attribute(const std::string& caption, const Value& value) {
 
   619       _writer_bits::ValueStorageBase* storage =
 
   620         new _writer_bits::ValueStorage<Value>(value);
 
   621       _attributes.push_back(std::make_pair(caption, storage));
 
   625     /// \brief Attribute writing rule
 
   627     /// Add an attribute writing rule with specialized converter to the
 
   629     template <typename Value, typename Converter>
 
   630     DigraphWriter& attribute(const std::string& caption, const Value& value,
 
   631                              const Converter& converter = Converter()) {
 
   632       _writer_bits::ValueStorageBase* storage =
 
   633         new _writer_bits::ValueStorage<Value, Converter>(value, converter);
 
   634       _attributes.push_back(std::make_pair(caption, storage));
 
   638     /// \brief Node writing rule
 
   640     /// Add a node writing rule to the writer.
 
   641     DigraphWriter& node(const std::string& caption, const Node& node) {
 
   642       typedef _writer_bits::MapLookUpConverter<Node> Converter;
 
   643       Converter converter(_node_index);
 
   644       _writer_bits::ValueStorageBase* storage =
 
   645         new _writer_bits::ValueStorage<Node, Converter>(node, converter);
 
   646       _attributes.push_back(std::make_pair(caption, storage));
 
   650     /// \brief Arc writing rule
 
   652     /// Add an arc writing rule to writer.
 
   653     DigraphWriter& arc(const std::string& caption, const Arc& arc) {
 
   654       typedef _writer_bits::MapLookUpConverter<Arc> Converter;
 
   655       Converter converter(_arc_index);
 
   656       _writer_bits::ValueStorageBase* storage =
 
   657         new _writer_bits::ValueStorage<Arc, Converter>(arc, converter);
 
   658       _attributes.push_back(std::make_pair(caption, storage));
 
   662     /// \name Section captions
 
   665     /// \brief Add an additional caption to the \c \@nodes section
 
   667     /// Add an additional caption to the \c \@nodes section.
 
   668     DigraphWriter& nodes(const std::string& caption) {
 
   669       _nodes_caption = caption;
 
   673     /// \brief Add an additional caption to the \c \@arcs section
 
   675     /// Add an additional caption to the \c \@arcs section.
 
   676     DigraphWriter& arcs(const std::string& caption) {
 
   677       _arcs_caption = caption;
 
   681     /// \brief Add an additional caption to the \c \@attributes section
 
   683     /// Add an additional caption to the \c \@attributes section.
 
   684     DigraphWriter& attributes(const std::string& caption) {
 
   685       _attributes_caption = caption;
 
   689     /// \name Skipping section
 
   692     /// \brief Skip writing the node set
 
   694     /// The \c \@nodes section will not be written to the stream.
 
   695     DigraphWriter& skipNodes() {
 
   696       LEMON_ASSERT(!_skip_nodes, "Multiple usage of skipNodes() member");
 
   701     /// \brief Skip writing arc set
 
   703     /// The \c \@arcs section will not be written to the stream.
 
   704     DigraphWriter& skipArcs() {
 
   705       LEMON_ASSERT(!_skip_arcs, "Multiple usage of skipArcs() member");
 
   715       _writer_bits::MapStorageBase<Node>* label = 0;
 
   716       for (typename NodeMaps::iterator it = _node_maps.begin();
 
   717            it != _node_maps.end(); ++it) {
 
   718         if (it->first == "label") {
 
   725       if (!_nodes_caption.empty()) {
 
   726         _writer_bits::writeToken(*_os << ' ', _nodes_caption);
 
   731         *_os << "label" << '\t';
 
   733       for (typename NodeMaps::iterator it = _node_maps.begin();
 
   734            it != _node_maps.end(); ++it) {
 
   735         _writer_bits::writeToken(*_os, it->first) << '\t';
 
   739       std::vector<Node> nodes;
 
   740       for (NodeIt n(_digraph); n != INVALID; ++n) {
 
   745         IdMap<Digraph, Node> id_map(_digraph);
 
   746         _writer_bits::MapLess<IdMap<Digraph, Node> > id_less(id_map);
 
   747         std::sort(nodes.begin(), nodes.end(), id_less);
 
   752       for (int i = 0; i < static_cast<int>(nodes.size()); ++i) {
 
   755           std::ostringstream os;
 
   756           os << _digraph.id(n);
 
   757           _writer_bits::writeToken(*_os, os.str());
 
   759           _node_index.insert(std::make_pair(n, os.str()));
 
   761         for (typename NodeMaps::iterator it = _node_maps.begin();
 
   762              it != _node_maps.end(); ++it) {
 
   763           std::string value = it->second->get(n);
 
   764           _writer_bits::writeToken(*_os, value);
 
   765           if (it->first == "label") {
 
   766             _node_index.insert(std::make_pair(n, value));
 
   774     void createNodeIndex() {
 
   775       _writer_bits::MapStorageBase<Node>* label = 0;
 
   776       for (typename NodeMaps::iterator it = _node_maps.begin();
 
   777            it != _node_maps.end(); ++it) {
 
   778         if (it->first == "label") {
 
   785         for (NodeIt n(_digraph); n != INVALID; ++n) {
 
   786           std::ostringstream os;
 
   787           os << _digraph.id(n);
 
   788           _node_index.insert(std::make_pair(n, os.str()));
 
   791         for (NodeIt n(_digraph); n != INVALID; ++n) {
 
   792           std::string value = label->get(n);
 
   793           _node_index.insert(std::make_pair(n, value));
 
   799       _writer_bits::MapStorageBase<Arc>* label = 0;
 
   800       for (typename ArcMaps::iterator it = _arc_maps.begin();
 
   801            it != _arc_maps.end(); ++it) {
 
   802         if (it->first == "label") {
 
   809       if (!_arcs_caption.empty()) {
 
   810         _writer_bits::writeToken(*_os << ' ', _arcs_caption);
 
   814       *_os << '\t' << '\t';
 
   816         *_os << "label" << '\t';
 
   818       for (typename ArcMaps::iterator it = _arc_maps.begin();
 
   819            it != _arc_maps.end(); ++it) {
 
   820         _writer_bits::writeToken(*_os, it->first) << '\t';
 
   824       std::vector<Arc> arcs;
 
   825       for (ArcIt n(_digraph); n != INVALID; ++n) {
 
   830         IdMap<Digraph, Arc> id_map(_digraph);
 
   831         _writer_bits::MapLess<IdMap<Digraph, Arc> > id_less(id_map);
 
   832         std::sort(arcs.begin(), arcs.end(), id_less);
 
   837       for (int i = 0; i < static_cast<int>(arcs.size()); ++i) {
 
   839         _writer_bits::writeToken(*_os, _node_index.
 
   840                                  find(_digraph.source(a))->second);
 
   842         _writer_bits::writeToken(*_os, _node_index.
 
   843                                  find(_digraph.target(a))->second);
 
   846           std::ostringstream os;
 
   847           os << _digraph.id(a);
 
   848           _writer_bits::writeToken(*_os, os.str());
 
   850           _arc_index.insert(std::make_pair(a, os.str()));
 
   852         for (typename ArcMaps::iterator it = _arc_maps.begin();
 
   853              it != _arc_maps.end(); ++it) {
 
   854           std::string value = it->second->get(a);
 
   855           _writer_bits::writeToken(*_os, value);
 
   856           if (it->first == "label") {
 
   857             _arc_index.insert(std::make_pair(a, value));
 
   865     void createArcIndex() {
 
   866       _writer_bits::MapStorageBase<Arc>* label = 0;
 
   867       for (typename ArcMaps::iterator it = _arc_maps.begin();
 
   868            it != _arc_maps.end(); ++it) {
 
   869         if (it->first == "label") {
 
   876         for (ArcIt a(_digraph); a != INVALID; ++a) {
 
   877           std::ostringstream os;
 
   878           os << _digraph.id(a);
 
   879           _arc_index.insert(std::make_pair(a, os.str()));
 
   882         for (ArcIt a(_digraph); a != INVALID; ++a) {
 
   883           std::string value = label->get(a);
 
   884           _arc_index.insert(std::make_pair(a, value));
 
   889     void writeAttributes() {
 
   890       if (_attributes.empty()) return;
 
   891       *_os << "@attributes";
 
   892       if (!_attributes_caption.empty()) {
 
   893         _writer_bits::writeToken(*_os << ' ', _attributes_caption);
 
   896       for (typename Attributes::iterator it = _attributes.begin();
 
   897            it != _attributes.end(); ++it) {
 
   898         _writer_bits::writeToken(*_os, it->first) << ' ';
 
   899         _writer_bits::writeToken(*_os, it->second->get());
 
   906     /// \name Execution of the writer
 
   909     /// \brief Start the batch processing
 
   911     /// This function starts the batch processing.
 
   926     /// \brief Give back the stream of the writer
 
   928     /// Give back the stream of the writer.
 
   929     std::ostream& ostream() {
 
   936   template <typename Graph>
 
   939   /// \brief Return a \ref GraphWriter class
 
   941   /// This function just returns a \ref GraphWriter class.
 
   942   /// \relates GraphWriter
 
   943   template <typename Graph>
 
   944   GraphWriter<Graph> graphWriter(const Graph& graph,
 
   945                                  std::ostream& os = std::cout) {
 
   946     GraphWriter<Graph> tmp(graph, os);
 
   950   /// \brief Return a \ref GraphWriter class
 
   952   /// This function just returns a \ref GraphWriter class.
 
   953   /// \relates GraphWriter
 
   954   template <typename Graph>
 
   955   GraphWriter<Graph> graphWriter(const Graph& graph, const std::string& fn) {
 
   956     GraphWriter<Graph> tmp(graph, fn);
 
   960   /// \brief Return a \ref GraphWriter class
 
   962   /// This function just returns a \ref GraphWriter class.
 
   963   /// \relates GraphWriter
 
   964   template <typename Graph>
 
   965   GraphWriter<Graph> graphWriter(const Graph& graph, const char* fn) {
 
   966     GraphWriter<Graph> tmp(graph, fn);
 
   970   /// \ingroup lemon_io
 
   972   /// \brief \ref lgf-format "LGF" writer for directed graphs
 
   974   /// This utility writes an \ref lgf-format "LGF" file.
 
   976   /// It can be used almost the same way as \c DigraphWriter.
 
   977   /// The only difference is that this class can handle edges and
 
   978   /// edge maps as well as arcs and arc maps.
 
   980   /// The arc maps are written into the file as two columns, the
 
   981   /// caption of the columns are the name of the map prefixed with \c
 
   982   /// '+' and \c '-'. The arcs are written into the \c \@attributes
 
   983   /// section as a \c '+' or a \c '-' prefix (depends on the direction
 
   984   /// of the arc) and the label of corresponding edge.
 
   985   template <typename _Graph>
 
   989     typedef _Graph Graph;
 
   990     TEMPLATE_GRAPH_TYPEDEFS(Graph);
 
  1000     std::string _nodes_caption;
 
  1001     std::string _edges_caption;
 
  1002     std::string _attributes_caption;
 
  1004     typedef std::map<Node, std::string> NodeIndex;
 
  1005     NodeIndex _node_index;
 
  1006     typedef std::map<Edge, std::string> EdgeIndex;
 
  1007     EdgeIndex _edge_index;
 
  1009     typedef std::vector<std::pair<std::string,
 
  1010       _writer_bits::MapStorageBase<Node>* > > NodeMaps;
 
  1011     NodeMaps _node_maps;
 
  1013     typedef std::vector<std::pair<std::string,
 
  1014       _writer_bits::MapStorageBase<Edge>* > >EdgeMaps;
 
  1015     EdgeMaps _edge_maps;
 
  1017     typedef std::vector<std::pair<std::string,
 
  1018       _writer_bits::ValueStorageBase*> > Attributes;
 
  1019     Attributes _attributes;
 
  1026     /// \brief Constructor
 
  1028     /// Construct a directed graph writer, which writes to the given
 
  1030     GraphWriter(const Graph& graph, std::ostream& os = std::cout)
 
  1031       : _os(&os), local_os(false), _graph(graph),
 
  1032         _skip_nodes(false), _skip_edges(false) {}
 
  1034     /// \brief Constructor
 
  1036     /// Construct a directed graph writer, which writes to the given
 
  1038     GraphWriter(const Graph& graph, const std::string& fn)
 
  1039       : _os(new std::ofstream(fn.c_str())), local_os(true), _graph(graph),
 
  1040         _skip_nodes(false), _skip_edges(false) {
 
  1043         throw IoError("Cannot write file", fn);
 
  1047     /// \brief Constructor
 
  1049     /// Construct a directed graph writer, which writes to the given
 
  1051     GraphWriter(const Graph& graph, const char* fn)
 
  1052       : _os(new std::ofstream(fn)), local_os(true), _graph(graph),
 
  1053         _skip_nodes(false), _skip_edges(false) {
 
  1056         throw IoError("Cannot write file", fn);
 
  1060     /// \brief Destructor
 
  1062       for (typename NodeMaps::iterator it = _node_maps.begin();
 
  1063            it != _node_maps.end(); ++it) {
 
  1067       for (typename EdgeMaps::iterator it = _edge_maps.begin();
 
  1068            it != _edge_maps.end(); ++it) {
 
  1072       for (typename Attributes::iterator it = _attributes.begin();
 
  1073            it != _attributes.end(); ++it) {
 
  1084     friend GraphWriter<Graph> graphWriter<>(const Graph& graph,
 
  1086     friend GraphWriter<Graph> graphWriter<>(const Graph& graph,
 
  1087                                             const std::string& fn);
 
  1088     friend GraphWriter<Graph> graphWriter<>(const Graph& graph,
 
  1091     GraphWriter(GraphWriter& other)
 
  1092       : _os(other._os), local_os(other.local_os), _graph(other._graph),
 
  1093         _skip_nodes(other._skip_nodes), _skip_edges(other._skip_edges) {
 
  1096       other.local_os = false;
 
  1098       _node_index.swap(other._node_index);
 
  1099       _edge_index.swap(other._edge_index);
 
  1101       _node_maps.swap(other._node_maps);
 
  1102       _edge_maps.swap(other._edge_maps);
 
  1103       _attributes.swap(other._attributes);
 
  1105       _nodes_caption = other._nodes_caption;
 
  1106       _edges_caption = other._edges_caption;
 
  1107       _attributes_caption = other._attributes_caption;
 
  1110     GraphWriter& operator=(const GraphWriter&);
 
  1114     /// \name Writing rules
 
  1117     /// \brief Node map writing rule
 
  1119     /// Add a node map writing rule to the writer.
 
  1120     template <typename Map>
 
  1121     GraphWriter& nodeMap(const std::string& caption, const Map& map) {
 
  1122       checkConcept<concepts::ReadMap<Node, typename Map::Value>, Map>();
 
  1123       _writer_bits::MapStorageBase<Node>* storage =
 
  1124         new _writer_bits::MapStorage<Node, Map>(map);
 
  1125       _node_maps.push_back(std::make_pair(caption, storage));
 
  1129     /// \brief Node map writing rule
 
  1131     /// Add a node map writing rule with specialized converter to the
 
  1133     template <typename Map, typename Converter>
 
  1134     GraphWriter& nodeMap(const std::string& caption, const Map& map,
 
  1135                            const Converter& converter = Converter()) {
 
  1136       checkConcept<concepts::ReadMap<Node, typename Map::Value>, Map>();
 
  1137       _writer_bits::MapStorageBase<Node>* storage =
 
  1138         new _writer_bits::MapStorage<Node, Map, Converter>(map, converter);
 
  1139       _node_maps.push_back(std::make_pair(caption, storage));
 
  1143     /// \brief Edge map writing rule
 
  1145     /// Add an edge map writing rule to the writer.
 
  1146     template <typename Map>
 
  1147     GraphWriter& edgeMap(const std::string& caption, const Map& map) {
 
  1148       checkConcept<concepts::ReadMap<Edge, typename Map::Value>, Map>();
 
  1149       _writer_bits::MapStorageBase<Edge>* storage =
 
  1150         new _writer_bits::MapStorage<Edge, Map>(map);
 
  1151       _edge_maps.push_back(std::make_pair(caption, storage));
 
  1155     /// \brief Edge map writing rule
 
  1157     /// Add an edge map writing rule with specialized converter to the
 
  1159     template <typename Map, typename Converter>
 
  1160     GraphWriter& edgeMap(const std::string& caption, const Map& map,
 
  1161                           const Converter& converter = Converter()) {
 
  1162       checkConcept<concepts::ReadMap<Edge, typename Map::Value>, Map>();
 
  1163       _writer_bits::MapStorageBase<Edge>* storage =
 
  1164         new _writer_bits::MapStorage<Edge, Map, Converter>(map, converter);
 
  1165       _edge_maps.push_back(std::make_pair(caption, storage));
 
  1169     /// \brief Arc map writing rule
 
  1171     /// Add an arc map writing rule to the writer.
 
  1172     template <typename Map>
 
  1173     GraphWriter& arcMap(const std::string& caption, const Map& map) {
 
  1174       checkConcept<concepts::ReadMap<Arc, typename Map::Value>, Map>();
 
  1175       _writer_bits::MapStorageBase<Edge>* forward_storage =
 
  1176         new _writer_bits::GraphArcMapStorage<Graph, true, Map>(_graph, map);
 
  1177       _edge_maps.push_back(std::make_pair('+' + caption, forward_storage));
 
  1178       _writer_bits::MapStorageBase<Edge>* backward_storage =
 
  1179         new _writer_bits::GraphArcMapStorage<Graph, false, Map>(_graph, map);
 
  1180       _edge_maps.push_back(std::make_pair('-' + caption, backward_storage));
 
  1184     /// \brief Arc map writing rule
 
  1186     /// Add an arc map writing rule with specialized converter to the
 
  1188     template <typename Map, typename Converter>
 
  1189     GraphWriter& arcMap(const std::string& caption, const Map& map,
 
  1190                           const Converter& converter = Converter()) {
 
  1191       checkConcept<concepts::ReadMap<Arc, typename Map::Value>, Map>();
 
  1192       _writer_bits::MapStorageBase<Edge>* forward_storage =
 
  1193         new _writer_bits::GraphArcMapStorage<Graph, true, Map, Converter>
 
  1194         (_graph, map, converter);
 
  1195       _edge_maps.push_back(std::make_pair('+' + caption, forward_storage));
 
  1196       _writer_bits::MapStorageBase<Edge>* backward_storage =
 
  1197         new _writer_bits::GraphArcMapStorage<Graph, false, Map, Converter>
 
  1198         (_graph, map, converter);
 
  1199       _edge_maps.push_back(std::make_pair('-' + caption, backward_storage));
 
  1203     /// \brief Attribute writing rule
 
  1205     /// Add an attribute writing rule to the writer.
 
  1206     template <typename Value>
 
  1207     GraphWriter& attribute(const std::string& caption, const Value& value) {
 
  1208       _writer_bits::ValueStorageBase* storage =
 
  1209         new _writer_bits::ValueStorage<Value>(value);
 
  1210       _attributes.push_back(std::make_pair(caption, storage));
 
  1214     /// \brief Attribute writing rule
 
  1216     /// Add an attribute writing rule with specialized converter to the
 
  1218     template <typename Value, typename Converter>
 
  1219     GraphWriter& attribute(const std::string& caption, const Value& value,
 
  1220                              const Converter& converter = Converter()) {
 
  1221       _writer_bits::ValueStorageBase* storage =
 
  1222         new _writer_bits::ValueStorage<Value, Converter>(value, converter);
 
  1223       _attributes.push_back(std::make_pair(caption, storage));
 
  1227     /// \brief Node writing rule
 
  1229     /// Add a node writing rule to the writer.
 
  1230     GraphWriter& node(const std::string& caption, const Node& node) {
 
  1231       typedef _writer_bits::MapLookUpConverter<Node> Converter;
 
  1232       Converter converter(_node_index);
 
  1233       _writer_bits::ValueStorageBase* storage =
 
  1234         new _writer_bits::ValueStorage<Node, Converter>(node, converter);
 
  1235       _attributes.push_back(std::make_pair(caption, storage));
 
  1239     /// \brief Edge writing rule
 
  1241     /// Add an edge writing rule to writer.
 
  1242     GraphWriter& edge(const std::string& caption, const Edge& edge) {
 
  1243       typedef _writer_bits::MapLookUpConverter<Edge> Converter;
 
  1244       Converter converter(_edge_index);
 
  1245       _writer_bits::ValueStorageBase* storage =
 
  1246         new _writer_bits::ValueStorage<Edge, Converter>(edge, converter);
 
  1247       _attributes.push_back(std::make_pair(caption, storage));
 
  1251     /// \brief Arc writing rule
 
  1253     /// Add an arc writing rule to writer.
 
  1254     GraphWriter& arc(const std::string& caption, const Arc& arc) {
 
  1255       typedef _writer_bits::GraphArcLookUpConverter<Graph> Converter;
 
  1256       Converter converter(_graph, _edge_index);
 
  1257       _writer_bits::ValueStorageBase* storage =
 
  1258         new _writer_bits::ValueStorage<Arc, Converter>(arc, converter);
 
  1259       _attributes.push_back(std::make_pair(caption, storage));
 
  1263     /// \name Section captions
 
  1266     /// \brief Add an additional caption to the \c \@nodes section
 
  1268     /// Add an additional caption to the \c \@nodes section.
 
  1269     GraphWriter& nodes(const std::string& caption) {
 
  1270       _nodes_caption = caption;
 
  1274     /// \brief Add an additional caption to the \c \@arcs section
 
  1276     /// Add an additional caption to the \c \@arcs section.
 
  1277     GraphWriter& edges(const std::string& caption) {
 
  1278       _edges_caption = caption;
 
  1282     /// \brief Add an additional caption to the \c \@attributes section
 
  1284     /// Add an additional caption to the \c \@attributes section.
 
  1285     GraphWriter& attributes(const std::string& caption) {
 
  1286       _attributes_caption = caption;
 
  1290     /// \name Skipping section
 
  1293     /// \brief Skip writing the node set
 
  1295     /// The \c \@nodes section will not be written to the stream.
 
  1296     GraphWriter& skipNodes() {
 
  1297       LEMON_ASSERT(!_skip_nodes, "Multiple usage of skipNodes() member");
 
  1302     /// \brief Skip writing edge set
 
  1304     /// The \c \@edges section will not be written to the stream.
 
  1305     GraphWriter& skipEdges() {
 
  1306       LEMON_ASSERT(!_skip_edges, "Multiple usage of skipEdges() member");
 
  1316       _writer_bits::MapStorageBase<Node>* label = 0;
 
  1317       for (typename NodeMaps::iterator it = _node_maps.begin();
 
  1318            it != _node_maps.end(); ++it) {
 
  1319         if (it->first == "label") {
 
  1326       if (!_nodes_caption.empty()) {
 
  1327         _writer_bits::writeToken(*_os << ' ', _nodes_caption);
 
  1332         *_os << "label" << '\t';
 
  1334       for (typename NodeMaps::iterator it = _node_maps.begin();
 
  1335            it != _node_maps.end(); ++it) {
 
  1336         _writer_bits::writeToken(*_os, it->first) << '\t';
 
  1340       std::vector<Node> nodes;
 
  1341       for (NodeIt n(_graph); n != INVALID; ++n) {
 
  1346         IdMap<Graph, Node> id_map(_graph);
 
  1347         _writer_bits::MapLess<IdMap<Graph, Node> > id_less(id_map);
 
  1348         std::sort(nodes.begin(), nodes.end(), id_less);
 
  1353       for (int i = 0; i < static_cast<int>(nodes.size()); ++i) {
 
  1356           std::ostringstream os;
 
  1358           _writer_bits::writeToken(*_os, os.str());
 
  1360           _node_index.insert(std::make_pair(n, os.str()));
 
  1362         for (typename NodeMaps::iterator it = _node_maps.begin();
 
  1363              it != _node_maps.end(); ++it) {
 
  1364           std::string value = it->second->get(n);
 
  1365           _writer_bits::writeToken(*_os, value);
 
  1366           if (it->first == "label") {
 
  1367             _node_index.insert(std::make_pair(n, value));
 
  1375     void createNodeIndex() {
 
  1376       _writer_bits::MapStorageBase<Node>* label = 0;
 
  1377       for (typename NodeMaps::iterator it = _node_maps.begin();
 
  1378            it != _node_maps.end(); ++it) {
 
  1379         if (it->first == "label") {
 
  1386         for (NodeIt n(_graph); n != INVALID; ++n) {
 
  1387           std::ostringstream os;
 
  1389           _node_index.insert(std::make_pair(n, os.str()));
 
  1392         for (NodeIt n(_graph); n != INVALID; ++n) {
 
  1393           std::string value = label->get(n);
 
  1394           _node_index.insert(std::make_pair(n, value));
 
  1400       _writer_bits::MapStorageBase<Edge>* label = 0;
 
  1401       for (typename EdgeMaps::iterator it = _edge_maps.begin();
 
  1402            it != _edge_maps.end(); ++it) {
 
  1403         if (it->first == "label") {
 
  1410       if (!_edges_caption.empty()) {
 
  1411         _writer_bits::writeToken(*_os << ' ', _edges_caption);
 
  1415       *_os << '\t' << '\t';
 
  1417         *_os << "label" << '\t';
 
  1419       for (typename EdgeMaps::iterator it = _edge_maps.begin();
 
  1420            it != _edge_maps.end(); ++it) {
 
  1421         _writer_bits::writeToken(*_os, it->first) << '\t';
 
  1425       std::vector<Edge> edges;
 
  1426       for (EdgeIt n(_graph); n != INVALID; ++n) {
 
  1431         IdMap<Graph, Edge> id_map(_graph);
 
  1432         _writer_bits::MapLess<IdMap<Graph, Edge> > id_less(id_map);
 
  1433         std::sort(edges.begin(), edges.end(), id_less);
 
  1438       for (int i = 0; i < static_cast<int>(edges.size()); ++i) {
 
  1440         _writer_bits::writeToken(*_os, _node_index.
 
  1441                                  find(_graph.u(e))->second);
 
  1443         _writer_bits::writeToken(*_os, _node_index.
 
  1444                                  find(_graph.v(e))->second);
 
  1447           std::ostringstream os;
 
  1449           _writer_bits::writeToken(*_os, os.str());
 
  1451           _edge_index.insert(std::make_pair(e, os.str()));
 
  1453         for (typename EdgeMaps::iterator it = _edge_maps.begin();
 
  1454              it != _edge_maps.end(); ++it) {
 
  1455           std::string value = it->second->get(e);
 
  1456           _writer_bits::writeToken(*_os, value);
 
  1457           if (it->first == "label") {
 
  1458             _edge_index.insert(std::make_pair(e, value));
 
  1466     void createEdgeIndex() {
 
  1467       _writer_bits::MapStorageBase<Edge>* label = 0;
 
  1468       for (typename EdgeMaps::iterator it = _edge_maps.begin();
 
  1469            it != _edge_maps.end(); ++it) {
 
  1470         if (it->first == "label") {
 
  1477         for (EdgeIt e(_graph); e != INVALID; ++e) {
 
  1478           std::ostringstream os;
 
  1480           _edge_index.insert(std::make_pair(e, os.str()));
 
  1483         for (EdgeIt e(_graph); e != INVALID; ++e) {
 
  1484           std::string value = label->get(e);
 
  1485           _edge_index.insert(std::make_pair(e, value));
 
  1490     void writeAttributes() {
 
  1491       if (_attributes.empty()) return;
 
  1492       *_os << "@attributes";
 
  1493       if (!_attributes_caption.empty()) {
 
  1494         _writer_bits::writeToken(*_os << ' ', _attributes_caption);
 
  1497       for (typename Attributes::iterator it = _attributes.begin();
 
  1498            it != _attributes.end(); ++it) {
 
  1499         _writer_bits::writeToken(*_os, it->first) << ' ';
 
  1500         _writer_bits::writeToken(*_os, it->second->get());
 
  1507     /// \name Execution of the writer
 
  1510     /// \brief Start the batch processing
 
  1512     /// This function starts the batch processing.
 
  1527     /// \brief Give back the stream of the writer
 
  1529     /// Give back the stream of the writer
 
  1530     std::ostream& ostream() {
 
  1537   class SectionWriter;
 
  1539   SectionWriter sectionWriter(std::istream& is);
 
  1540   SectionWriter sectionWriter(const std::string& fn);
 
  1541   SectionWriter sectionWriter(const char* fn);
 
  1543   /// \ingroup lemon_io
 
  1545   /// \brief Section writer class
 
  1547   /// In the \ref lgf-format "LGF" file extra sections can be placed,
 
  1548   /// which contain any data in arbitrary format. Such sections can be
 
  1549   /// written with this class. A writing rule can be added to the
 
  1550   /// class with two different functions. With the \c sectionLines()
 
  1551   /// function a generator can write the section line-by-line, while
 
  1552   /// with the \c sectionStream() member the section can be written to
 
  1553   /// an output stream.
 
  1554   class SectionWriter {
 
  1560     typedef std::vector<std::pair<std::string, _writer_bits::Section*> >
 
  1567     /// \brief Constructor
 
  1569     /// Construct a section writer, which writes to the given output
 
  1571     SectionWriter(std::ostream& os)
 
  1572       : _os(&os), local_os(false) {}
 
  1574     /// \brief Constructor
 
  1576     /// Construct a section writer, which writes into the given file.
 
  1577     SectionWriter(const std::string& fn)
 
  1578       : _os(new std::ofstream(fn.c_str())), local_os(true) {
 
  1581         throw IoError("Cannot write file", fn);
 
  1585     /// \brief Constructor
 
  1587     /// Construct a section writer, which writes into the given file.
 
  1588     SectionWriter(const char* fn)
 
  1589       : _os(new std::ofstream(fn)), local_os(true) {
 
  1592         throw IoError("Cannot write file", fn);
 
  1596     /// \brief Destructor
 
  1598       for (Sections::iterator it = _sections.begin();
 
  1599            it != _sections.end(); ++it) {
 
  1611     friend SectionWriter sectionWriter(std::ostream& os);
 
  1612     friend SectionWriter sectionWriter(const std::string& fn);
 
  1613     friend SectionWriter sectionWriter(const char* fn);
 
  1615     SectionWriter(SectionWriter& other)
 
  1616       : _os(other._os), local_os(other.local_os) {
 
  1619       other.local_os = false;
 
  1621       _sections.swap(other._sections);
 
  1624     SectionWriter& operator=(const SectionWriter&);
 
  1628     /// \name Section writers
 
  1631     /// \brief Add a section writer with line oriented writing
 
  1633     /// The first parameter is the type descriptor of the section, the
 
  1634     /// second is a generator with std::string values. At the writing
 
  1635     /// process, the returned \c std::string will be written into the
 
  1636     /// output file until it is an empty string.
 
  1638     /// For example, an integer vector is written into a section.
 
  1646     /// The generator is implemented as a struct.
 
  1648     ///  struct NumberSection {
 
  1649     ///    std::vector<int>::const_iterator _it, _end;
 
  1650     ///    NumberSection(const std::vector<int>& data)
 
  1651     ///      : _it(data.begin()), _end(data.end()) {}
 
  1652     ///    std::string operator()() {
 
  1653     ///      int rem_in_line = 4;
 
  1654     ///      std::ostringstream ls;
 
  1655     ///      while (rem_in_line > 0 && _it != _end) {
 
  1656     ///        ls << *(_it++) << ' ';
 
  1659     ///      return ls.str();
 
  1665     ///  writer.sectionLines("numbers", NumberSection(vec));
 
  1667     template <typename Functor>
 
  1668     SectionWriter& sectionLines(const std::string& type, Functor functor) {
 
  1669       LEMON_ASSERT(!type.empty(), "Type is empty.");
 
  1670       _sections.push_back(std::make_pair(type,
 
  1671         new _writer_bits::LineSection<Functor>(functor)));
 
  1676     /// \brief Add a section writer with stream oriented writing
 
  1678     /// The first parameter is the type of the section, the second is
 
  1679     /// a functor, which takes a \c std::ostream& parameter. The
 
  1680     /// functor writes the section to the output stream.
 
  1681     /// \warning The last line must be closed with end-line character.
 
  1682     template <typename Functor>
 
  1683     SectionWriter& sectionStream(const std::string& type, Functor functor) {
 
  1684       LEMON_ASSERT(!type.empty(), "Type is empty.");
 
  1685       _sections.push_back(std::make_pair(type,
 
  1686          new _writer_bits::StreamSection<Functor>(functor)));
 
  1695     /// \name Execution of the writer
 
  1698     /// \brief Start the batch processing
 
  1700     /// This function starts the batch processing.
 
  1703       LEMON_ASSERT(_os != 0, "This writer is assigned to an other writer");
 
  1705       for (Sections::iterator it = _sections.begin();
 
  1706            it != _sections.end(); ++it) {
 
  1707         (*_os) << '@' << it->first << std::endl;
 
  1708         it->second->process(*_os);
 
  1712     /// \brief Give back the stream of the writer
 
  1714     /// Returns the stream of the writer
 
  1715     std::ostream& ostream() {
 
  1723   /// \brief Return a \ref SectionWriter class
 
  1725   /// This function just returns a \ref SectionWriter class.
 
  1726   /// \relates SectionWriter
 
  1727   inline SectionWriter sectionWriter(std::ostream& os) {
 
  1728     SectionWriter tmp(os);
 
  1732   /// \brief Return a \ref SectionWriter class
 
  1734   /// This function just returns a \ref SectionWriter class.
 
  1735   /// \relates SectionWriter
 
  1736   inline SectionWriter sectionWriter(const std::string& fn) {
 
  1737     SectionWriter tmp(fn);
 
  1741   /// \brief Return a \ref SectionWriter class
 
  1743   /// This function just returns a \ref SectionWriter class.
 
  1744   /// \relates SectionWriter
 
  1745   inline SectionWriter sectionWriter(const char* fn) {
 
  1746     SectionWriter tmp(fn);