lemon/lgf_writer.h
author Peter Kovacs <kpeter@inf.elte.hu>
Thu, 09 Oct 2008 10:09:44 +0200
changeset 313 64f8f7cc6168
parent 295 7c796c1cf1b0
child 319 5e12d7734036
permissions -rw-r--r--
Fix several doxygen warnings
     1 /* -*- mode: C++; indent-tabs-mode: nil; -*-
     2  *
     3  * This file is a part of LEMON, a generic C++ optimization library.
     4  *
     5  * Copyright (C) 2003-2008
     6  * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
     7  * (Egervary Research Group on Combinatorial Optimization, EGRES).
     8  *
     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.
    12  *
    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
    15  * purpose.
    16  *
    17  */
    18 
    19 ///\ingroup lemon_io
    20 ///\file
    21 ///\brief \ref lgf-format "LEMON Graph Format" writer.
    22 
    23 
    24 #ifndef LEMON_LGF_WRITER_H
    25 #define LEMON_LGF_WRITER_H
    26 
    27 #include <iostream>
    28 #include <fstream>
    29 #include <sstream>
    30 
    31 #include <algorithm>
    32 
    33 #include <vector>
    34 #include <functional>
    35 
    36 #include <lemon/assert.h>
    37 #include <lemon/core.h>
    38 #include <lemon/maps.h>
    39 
    40 #include <lemon/concept_check.h>
    41 #include <lemon/concepts/maps.h>
    42 
    43 namespace lemon {
    44 
    45   namespace _writer_bits {
    46 
    47     template <typename Value>
    48     struct DefaultConverter {
    49       std::string operator()(const Value& value) {
    50         std::ostringstream os;
    51         os << value;
    52         return os.str();
    53       }
    54     };
    55 
    56     template <typename T>
    57     bool operator<(const T&, const T&) {
    58       throw FormatError("Label map is not comparable");
    59     }
    60 
    61     template <typename _Map>
    62     class MapLess {
    63     public:
    64       typedef _Map Map;
    65       typedef typename Map::Key Item;
    66 
    67     private:
    68       const Map& _map;
    69 
    70     public:
    71       MapLess(const Map& map) : _map(map) {}
    72 
    73       bool operator()(const Item& left, const Item& right) {
    74         return _map[left] < _map[right];
    75       }
    76     };
    77 
    78     template <typename _Graph, bool _dir, typename _Map>
    79     class GraphArcMapLess {
    80     public:
    81       typedef _Map Map;
    82       typedef _Graph Graph;
    83       typedef typename Graph::Edge Item;
    84 
    85     private:
    86       const Graph& _graph;
    87       const Map& _map;
    88 
    89     public:
    90       GraphArcMapLess(const Graph& graph, const Map& map)
    91         : _graph(graph), _map(map) {}
    92 
    93       bool operator()(const Item& left, const Item& right) {
    94         return _map[_graph.direct(left, _dir)] <
    95           _map[_graph.direct(right, _dir)];
    96       }
    97     };
    98 
    99     template <typename _Item>
   100     class MapStorageBase {
   101     public:
   102       typedef _Item Item;
   103 
   104     public:
   105       MapStorageBase() {}
   106       virtual ~MapStorageBase() {}
   107 
   108       virtual std::string get(const Item& item) = 0;
   109       virtual void sort(std::vector<Item>&) = 0;
   110     };
   111 
   112     template <typename _Item, typename _Map,
   113               typename _Converter = DefaultConverter<typename _Map::Value> >
   114     class MapStorage : public MapStorageBase<_Item> {
   115     public:
   116       typedef _Map Map;
   117       typedef _Converter Converter;
   118       typedef _Item Item;
   119 
   120     private:
   121       const Map& _map;
   122       Converter _converter;
   123 
   124     public:
   125       MapStorage(const Map& map, const Converter& converter = Converter())
   126         : _map(map), _converter(converter) {}
   127       virtual ~MapStorage() {}
   128 
   129       virtual std::string get(const Item& item) {
   130         return _converter(_map[item]);
   131       }
   132       virtual void sort(std::vector<Item>& items) {
   133         MapLess<Map> less(_map);
   134         std::sort(items.begin(), items.end(), less);
   135       }
   136     };
   137 
   138     template <typename _Graph, bool _dir, typename _Map,
   139               typename _Converter = DefaultConverter<typename _Map::Value> >
   140     class GraphArcMapStorage : public MapStorageBase<typename _Graph::Edge> {
   141     public:
   142       typedef _Map Map;
   143       typedef _Converter Converter;
   144       typedef _Graph Graph;
   145       typedef typename Graph::Edge Item;
   146       static const bool dir = _dir;
   147 
   148     private:
   149       const Graph& _graph;
   150       const Map& _map;
   151       Converter _converter;
   152 
   153     public:
   154       GraphArcMapStorage(const Graph& graph, const Map& map,
   155                          const Converter& converter = Converter())
   156         : _graph(graph), _map(map), _converter(converter) {}
   157       virtual ~GraphArcMapStorage() {}
   158 
   159       virtual std::string get(const Item& item) {
   160         return _converter(_map[_graph.direct(item, dir)]);
   161       }
   162       virtual void sort(std::vector<Item>& items) {
   163         GraphArcMapLess<Graph, dir, Map> less(_graph, _map);
   164         std::sort(items.begin(), items.end(), less);
   165       }
   166     };
   167 
   168     class ValueStorageBase {
   169     public:
   170       ValueStorageBase() {}
   171       virtual ~ValueStorageBase() {}
   172 
   173       virtual std::string get() = 0;
   174     };
   175 
   176     template <typename _Value, typename _Converter = DefaultConverter<_Value> >
   177     class ValueStorage : public ValueStorageBase {
   178     public:
   179       typedef _Value Value;
   180       typedef _Converter Converter;
   181 
   182     private:
   183       const Value& _value;
   184       Converter _converter;
   185 
   186     public:
   187       ValueStorage(const Value& value, const Converter& converter = Converter())
   188         : _value(value), _converter(converter) {}
   189 
   190       virtual std::string get() {
   191         return _converter(_value);
   192       }
   193     };
   194 
   195     template <typename Value>
   196     struct MapLookUpConverter {
   197       const std::map<Value, std::string>& _map;
   198 
   199       MapLookUpConverter(const std::map<Value, std::string>& map)
   200         : _map(map) {}
   201 
   202       std::string operator()(const Value& str) {
   203         typename std::map<Value, std::string>::const_iterator it =
   204           _map.find(str);
   205         if (it == _map.end()) {
   206           throw FormatError("Item not found");
   207         }
   208         return it->second;
   209       }
   210     };
   211 
   212     template <typename Graph>
   213     struct GraphArcLookUpConverter {
   214       const Graph& _graph;
   215       const std::map<typename Graph::Edge, std::string>& _map;
   216 
   217       GraphArcLookUpConverter(const Graph& graph,
   218                               const std::map<typename Graph::Edge,
   219                                              std::string>& map)
   220         : _graph(graph), _map(map) {}
   221 
   222       std::string operator()(const typename Graph::Arc& val) {
   223         typename std::map<typename Graph::Edge, std::string>
   224           ::const_iterator it = _map.find(val);
   225         if (it == _map.end()) {
   226           throw FormatError("Item not found");
   227         }
   228         return (_graph.direction(val) ? '+' : '-') + it->second;
   229       }
   230     };
   231 
   232     inline bool isWhiteSpace(char c) {
   233       return c == ' ' || c == '\t' || c == '\v' ||
   234         c == '\n' || c == '\r' || c == '\f';
   235     }
   236 
   237     inline bool isEscaped(char c) {
   238       return c == '\\' || c == '\"' || c == '\'' ||
   239         c == '\a' || c == '\b';
   240     }
   241 
   242     inline static void writeEscape(std::ostream& os, char c) {
   243       switch (c) {
   244       case '\\':
   245         os << "\\\\";
   246         return;
   247       case '\"':
   248         os << "\\\"";
   249         return;
   250       case '\a':
   251         os << "\\a";
   252         return;
   253       case '\b':
   254         os << "\\b";
   255         return;
   256       case '\f':
   257         os << "\\f";
   258         return;
   259       case '\r':
   260         os << "\\r";
   261         return;
   262       case '\n':
   263         os << "\\n";
   264         return;
   265       case '\t':
   266         os << "\\t";
   267         return;
   268       case '\v':
   269         os << "\\v";
   270         return;
   271       default:
   272         if (c < 0x20) {
   273           std::ios::fmtflags flags = os.flags();
   274           os << '\\' << std::oct << static_cast<int>(c);
   275           os.flags(flags);
   276         } else {
   277           os << c;
   278         }
   279         return;
   280       }
   281     }
   282 
   283     inline bool requireEscape(const std::string& str) {
   284       if (str.empty() || str[0] == '@') return true;
   285       std::istringstream is(str);
   286       char c;
   287       while (is.get(c)) {
   288         if (isWhiteSpace(c) || isEscaped(c)) {
   289           return true;
   290         }
   291       }
   292       return false;
   293     }
   294 
   295     inline std::ostream& writeToken(std::ostream& os, const std::string& str) {
   296 
   297       if (requireEscape(str)) {
   298         os << '\"';
   299         for (std::string::const_iterator it = str.begin();
   300              it != str.end(); ++it) {
   301           writeEscape(os, *it);
   302         }
   303         os << '\"';
   304       } else {
   305         os << str;
   306       }
   307       return os;
   308     }
   309 
   310     class Section {
   311     public:
   312       virtual ~Section() {}
   313       virtual void process(std::ostream& os) = 0;
   314     };
   315 
   316     template <typename Functor>
   317     class LineSection : public Section {
   318     private:
   319 
   320       Functor _functor;
   321 
   322     public:
   323 
   324       LineSection(const Functor& functor) : _functor(functor) {}
   325       virtual ~LineSection() {}
   326 
   327       virtual void process(std::ostream& os) {
   328         std::string line;
   329         while (!(line = _functor()).empty()) os << line << std::endl;
   330       }
   331     };
   332 
   333     template <typename Functor>
   334     class StreamSection : public Section {
   335     private:
   336 
   337       Functor _functor;
   338 
   339     public:
   340 
   341       StreamSection(const Functor& functor) : _functor(functor) {}
   342       virtual ~StreamSection() {}
   343 
   344       virtual void process(std::ostream& os) {
   345         _functor(os);
   346       }
   347     };
   348 
   349   }
   350 
   351   template <typename Digraph>
   352   class DigraphWriter;
   353 
   354   /// \brief Return a \ref DigraphWriter class
   355   ///
   356   /// This function just returns a \ref DigraphWriter class.
   357   /// \relates DigraphWriter
   358   template <typename Digraph>
   359   DigraphWriter<Digraph> digraphWriter(const Digraph& digraph,
   360                                        std::ostream& os = std::cout) {
   361     DigraphWriter<Digraph> tmp(digraph, os);
   362     return tmp;
   363   }
   364 
   365   /// \brief Return a \ref DigraphWriter class
   366   ///
   367   /// This function just returns a \ref DigraphWriter class.
   368   /// \relates DigraphWriter
   369   template <typename Digraph>
   370   DigraphWriter<Digraph> digraphWriter(const Digraph& digraph,
   371                                        const std::string& fn) {
   372     DigraphWriter<Digraph> tmp(digraph, fn);
   373     return tmp;
   374   }
   375 
   376   /// \brief Return a \ref DigraphWriter class
   377   ///
   378   /// This function just returns a \ref DigraphWriter class.
   379   /// \relates DigraphWriter
   380   template <typename Digraph>
   381   DigraphWriter<Digraph> digraphWriter(const Digraph& digraph,
   382                                        const char* fn) {
   383     DigraphWriter<Digraph> tmp(digraph, fn);
   384     return tmp;
   385   }
   386 
   387   /// \ingroup lemon_io
   388   ///
   389   /// \brief \ref lgf-format "LGF" writer for directed graphs
   390   ///
   391   /// This utility writes an \ref lgf-format "LGF" file.
   392   ///
   393   /// The writing method does a batch processing. The user creates a
   394   /// writer object, then various writing rules can be added to the
   395   /// writer, and eventually the writing is executed with the \c run()
   396   /// member function. A map writing rule can be added to the writer
   397   /// with the \c nodeMap() or \c arcMap() members. An optional
   398   /// converter parameter can also be added as a standard functor
   399   /// converting from the value type of the map to \c std::string. If it
   400   /// is set, it will determine how the value type of the map is written to
   401   /// the output stream. If the functor is not set, then a default
   402   /// conversion will be used. The \c attribute(), \c node() and \c
   403   /// arc() functions are used to add attribute writing rules.
   404   ///
   405   ///\code
   406   /// DigraphWriter<Digraph>(digraph, std::cout).
   407   ///   nodeMap("coordinates", coord_map).
   408   ///   nodeMap("size", size).
   409   ///   nodeMap("title", title).
   410   ///   arcMap("capacity", cap_map).
   411   ///   node("source", src).
   412   ///   node("target", trg).
   413   ///   attribute("caption", caption).
   414   ///   run();
   415   ///\endcode
   416   ///
   417   ///
   418   /// By default, the writer does not write additional captions to the
   419   /// sections, but they can be give as an optional parameter of
   420   /// the \c nodes(), \c arcs() or \c
   421   /// attributes() functions.
   422   ///
   423   /// The \c skipNodes() and \c skipArcs() functions forbid the
   424   /// writing of the sections. If two arc sections should be written
   425   /// to the output, it can be done in two passes, the first pass
   426   /// writes the node section and the first arc section, then the
   427   /// second pass skips the node section and writes just the arc
   428   /// section to the stream. The output stream can be retrieved with
   429   /// the \c ostream() function, hence the second pass can append its
   430   /// output to the output of the first pass.
   431   template <typename _Digraph>
   432   class DigraphWriter {
   433   public:
   434 
   435     typedef _Digraph Digraph;
   436     TEMPLATE_DIGRAPH_TYPEDEFS(Digraph);
   437 
   438   private:
   439 
   440 
   441     std::ostream* _os;
   442     bool local_os;
   443 
   444     const Digraph& _digraph;
   445 
   446     std::string _nodes_caption;
   447     std::string _arcs_caption;
   448     std::string _attributes_caption;
   449 
   450     typedef std::map<Node, std::string> NodeIndex;
   451     NodeIndex _node_index;
   452     typedef std::map<Arc, std::string> ArcIndex;
   453     ArcIndex _arc_index;
   454 
   455     typedef std::vector<std::pair<std::string,
   456       _writer_bits::MapStorageBase<Node>* > > NodeMaps;
   457     NodeMaps _node_maps;
   458 
   459     typedef std::vector<std::pair<std::string,
   460       _writer_bits::MapStorageBase<Arc>* > >ArcMaps;
   461     ArcMaps _arc_maps;
   462 
   463     typedef std::vector<std::pair<std::string,
   464       _writer_bits::ValueStorageBase*> > Attributes;
   465     Attributes _attributes;
   466 
   467     bool _skip_nodes;
   468     bool _skip_arcs;
   469 
   470   public:
   471 
   472     /// \brief Constructor
   473     ///
   474     /// Construct a directed graph writer, which writes to the given
   475     /// output stream.
   476     DigraphWriter(const Digraph& digraph, std::ostream& os = std::cout)
   477       : _os(&os), local_os(false), _digraph(digraph),
   478         _skip_nodes(false), _skip_arcs(false) {}
   479 
   480     /// \brief Constructor
   481     ///
   482     /// Construct a directed graph writer, which writes to the given
   483     /// output file.
   484     DigraphWriter(const Digraph& digraph, const std::string& fn)
   485       : _os(new std::ofstream(fn.c_str())), local_os(true), _digraph(digraph),
   486         _skip_nodes(false), _skip_arcs(false) {
   487       if (!(*_os)) {
   488         delete _os;
   489         throw IoError("Cannot write file", fn);
   490       }
   491     }
   492 
   493     /// \brief Constructor
   494     ///
   495     /// Construct a directed graph writer, which writes to the given
   496     /// output file.
   497     DigraphWriter(const Digraph& digraph, const char* fn)
   498       : _os(new std::ofstream(fn)), local_os(true), _digraph(digraph),
   499         _skip_nodes(false), _skip_arcs(false) {
   500       if (!(*_os)) {
   501         delete _os;
   502         throw IoError("Cannot write file", fn);
   503       }
   504     }
   505 
   506     /// \brief Destructor
   507     ~DigraphWriter() {
   508       for (typename NodeMaps::iterator it = _node_maps.begin();
   509            it != _node_maps.end(); ++it) {
   510         delete it->second;
   511       }
   512 
   513       for (typename ArcMaps::iterator it = _arc_maps.begin();
   514            it != _arc_maps.end(); ++it) {
   515         delete it->second;
   516       }
   517 
   518       for (typename Attributes::iterator it = _attributes.begin();
   519            it != _attributes.end(); ++it) {
   520         delete it->second;
   521       }
   522 
   523       if (local_os) {
   524         delete _os;
   525       }
   526     }
   527 
   528   private:
   529 
   530     friend DigraphWriter<Digraph> digraphWriter<>(const Digraph& digraph,
   531                                                   std::ostream& os);
   532     friend DigraphWriter<Digraph> digraphWriter<>(const Digraph& digraph,
   533                                                   const std::string& fn);
   534     friend DigraphWriter<Digraph> digraphWriter<>(const Digraph& digraph,
   535                                                   const char *fn);
   536 
   537     DigraphWriter(DigraphWriter& other)
   538       : _os(other._os), local_os(other.local_os), _digraph(other._digraph),
   539         _skip_nodes(other._skip_nodes), _skip_arcs(other._skip_arcs) {
   540 
   541       other._os = 0;
   542       other.local_os = false;
   543 
   544       _node_index.swap(other._node_index);
   545       _arc_index.swap(other._arc_index);
   546 
   547       _node_maps.swap(other._node_maps);
   548       _arc_maps.swap(other._arc_maps);
   549       _attributes.swap(other._attributes);
   550 
   551       _nodes_caption = other._nodes_caption;
   552       _arcs_caption = other._arcs_caption;
   553       _attributes_caption = other._attributes_caption;
   554     }
   555 
   556     DigraphWriter& operator=(const DigraphWriter&);
   557 
   558   public:
   559 
   560     /// \name Writing rules
   561     /// @{
   562 
   563     /// \brief Node map writing rule
   564     ///
   565     /// Add a node map writing rule to the writer.
   566     template <typename Map>
   567     DigraphWriter& nodeMap(const std::string& caption, const Map& map) {
   568       checkConcept<concepts::ReadMap<Node, typename Map::Value>, Map>();
   569       _writer_bits::MapStorageBase<Node>* storage =
   570         new _writer_bits::MapStorage<Node, Map>(map);
   571       _node_maps.push_back(std::make_pair(caption, storage));
   572       return *this;
   573     }
   574 
   575     /// \brief Node map writing rule
   576     ///
   577     /// Add a node map writing rule with specialized converter to the
   578     /// writer.
   579     template <typename Map, typename Converter>
   580     DigraphWriter& nodeMap(const std::string& caption, const Map& map,
   581                            const Converter& converter = Converter()) {
   582       checkConcept<concepts::ReadMap<Node, typename Map::Value>, Map>();
   583       _writer_bits::MapStorageBase<Node>* storage =
   584         new _writer_bits::MapStorage<Node, Map, Converter>(map, converter);
   585       _node_maps.push_back(std::make_pair(caption, storage));
   586       return *this;
   587     }
   588 
   589     /// \brief Arc map writing rule
   590     ///
   591     /// Add an arc map writing rule to the writer.
   592     template <typename Map>
   593     DigraphWriter& arcMap(const std::string& caption, const Map& map) {
   594       checkConcept<concepts::ReadMap<Arc, typename Map::Value>, Map>();
   595       _writer_bits::MapStorageBase<Arc>* storage =
   596         new _writer_bits::MapStorage<Arc, Map>(map);
   597       _arc_maps.push_back(std::make_pair(caption, storage));
   598       return *this;
   599     }
   600 
   601     /// \brief Arc map writing rule
   602     ///
   603     /// Add an arc map writing rule with specialized converter to the
   604     /// writer.
   605     template <typename Map, typename Converter>
   606     DigraphWriter& arcMap(const std::string& caption, const Map& map,
   607                           const Converter& converter = Converter()) {
   608       checkConcept<concepts::ReadMap<Arc, typename Map::Value>, Map>();
   609       _writer_bits::MapStorageBase<Arc>* storage =
   610         new _writer_bits::MapStorage<Arc, Map, Converter>(map, converter);
   611       _arc_maps.push_back(std::make_pair(caption, storage));
   612       return *this;
   613     }
   614 
   615     /// \brief Attribute writing rule
   616     ///
   617     /// Add an attribute writing rule to the writer.
   618     template <typename Value>
   619     DigraphWriter& attribute(const std::string& caption, const Value& value) {
   620       _writer_bits::ValueStorageBase* storage =
   621         new _writer_bits::ValueStorage<Value>(value);
   622       _attributes.push_back(std::make_pair(caption, storage));
   623       return *this;
   624     }
   625 
   626     /// \brief Attribute writing rule
   627     ///
   628     /// Add an attribute writing rule with specialized converter to the
   629     /// writer.
   630     template <typename Value, typename Converter>
   631     DigraphWriter& attribute(const std::string& caption, const Value& value,
   632                              const Converter& converter = Converter()) {
   633       _writer_bits::ValueStorageBase* storage =
   634         new _writer_bits::ValueStorage<Value, Converter>(value, converter);
   635       _attributes.push_back(std::make_pair(caption, storage));
   636       return *this;
   637     }
   638 
   639     /// \brief Node writing rule
   640     ///
   641     /// Add a node writing rule to the writer.
   642     DigraphWriter& node(const std::string& caption, const Node& node) {
   643       typedef _writer_bits::MapLookUpConverter<Node> Converter;
   644       Converter converter(_node_index);
   645       _writer_bits::ValueStorageBase* storage =
   646         new _writer_bits::ValueStorage<Node, Converter>(node, converter);
   647       _attributes.push_back(std::make_pair(caption, storage));
   648       return *this;
   649     }
   650 
   651     /// \brief Arc writing rule
   652     ///
   653     /// Add an arc writing rule to writer.
   654     DigraphWriter& arc(const std::string& caption, const Arc& arc) {
   655       typedef _writer_bits::MapLookUpConverter<Arc> Converter;
   656       Converter converter(_arc_index);
   657       _writer_bits::ValueStorageBase* storage =
   658         new _writer_bits::ValueStorage<Arc, Converter>(arc, converter);
   659       _attributes.push_back(std::make_pair(caption, storage));
   660       return *this;
   661     }
   662 
   663     /// \name Section captions
   664     /// @{
   665 
   666     /// \brief Add an additional caption to the \c \@nodes section
   667     ///
   668     /// Add an additional caption to the \c \@nodes section.
   669     DigraphWriter& nodes(const std::string& caption) {
   670       _nodes_caption = caption;
   671       return *this;
   672     }
   673 
   674     /// \brief Add an additional caption to the \c \@arcs section
   675     ///
   676     /// Add an additional caption to the \c \@arcs section.
   677     DigraphWriter& arcs(const std::string& caption) {
   678       _arcs_caption = caption;
   679       return *this;
   680     }
   681 
   682     /// \brief Add an additional caption to the \c \@attributes section
   683     ///
   684     /// Add an additional caption to the \c \@attributes section.
   685     DigraphWriter& attributes(const std::string& caption) {
   686       _attributes_caption = caption;
   687       return *this;
   688     }
   689 
   690     /// \name Skipping section
   691     /// @{
   692 
   693     /// \brief Skip writing the node set
   694     ///
   695     /// The \c \@nodes section will not be written to the stream.
   696     DigraphWriter& skipNodes() {
   697       LEMON_ASSERT(!_skip_nodes, "Multiple usage of skipNodes() member");
   698       _skip_nodes = true;
   699       return *this;
   700     }
   701 
   702     /// \brief Skip writing arc set
   703     ///
   704     /// The \c \@arcs section will not be written to the stream.
   705     DigraphWriter& skipArcs() {
   706       LEMON_ASSERT(!_skip_arcs, "Multiple usage of skipArcs() member");
   707       _skip_arcs = true;
   708       return *this;
   709     }
   710 
   711     /// @}
   712 
   713   private:
   714 
   715     void writeNodes() {
   716       _writer_bits::MapStorageBase<Node>* label = 0;
   717       for (typename NodeMaps::iterator it = _node_maps.begin();
   718            it != _node_maps.end(); ++it) {
   719         if (it->first == "label") {
   720           label = it->second;
   721           break;
   722         }
   723       }
   724 
   725       *_os << "@nodes";
   726       if (!_nodes_caption.empty()) {
   727         _writer_bits::writeToken(*_os << ' ', _nodes_caption);
   728       }
   729       *_os << std::endl;
   730 
   731       if (label == 0) {
   732         *_os << "label" << '\t';
   733       }
   734       for (typename NodeMaps::iterator it = _node_maps.begin();
   735            it != _node_maps.end(); ++it) {
   736         _writer_bits::writeToken(*_os, it->first) << '\t';
   737       }
   738       *_os << std::endl;
   739 
   740       std::vector<Node> nodes;
   741       for (NodeIt n(_digraph); n != INVALID; ++n) {
   742         nodes.push_back(n);
   743       }
   744 
   745       if (label == 0) {
   746         IdMap<Digraph, Node> id_map(_digraph);
   747         _writer_bits::MapLess<IdMap<Digraph, Node> > id_less(id_map);
   748         std::sort(nodes.begin(), nodes.end(), id_less);
   749       } else {
   750         label->sort(nodes);
   751       }
   752 
   753       for (int i = 0; i < static_cast<int>(nodes.size()); ++i) {
   754         Node n = nodes[i];
   755         if (label == 0) {
   756           std::ostringstream os;
   757           os << _digraph.id(n);
   758           _writer_bits::writeToken(*_os, os.str());
   759           *_os << '\t';
   760           _node_index.insert(std::make_pair(n, os.str()));
   761         }
   762         for (typename NodeMaps::iterator it = _node_maps.begin();
   763              it != _node_maps.end(); ++it) {
   764           std::string value = it->second->get(n);
   765           _writer_bits::writeToken(*_os, value);
   766           if (it->first == "label") {
   767             _node_index.insert(std::make_pair(n, value));
   768           }
   769           *_os << '\t';
   770         }
   771         *_os << std::endl;
   772       }
   773     }
   774 
   775     void createNodeIndex() {
   776       _writer_bits::MapStorageBase<Node>* label = 0;
   777       for (typename NodeMaps::iterator it = _node_maps.begin();
   778            it != _node_maps.end(); ++it) {
   779         if (it->first == "label") {
   780           label = it->second;
   781           break;
   782         }
   783       }
   784 
   785       if (label == 0) {
   786         for (NodeIt n(_digraph); n != INVALID; ++n) {
   787           std::ostringstream os;
   788           os << _digraph.id(n);
   789           _node_index.insert(std::make_pair(n, os.str()));
   790         }
   791       } else {
   792         for (NodeIt n(_digraph); n != INVALID; ++n) {
   793           std::string value = label->get(n);
   794           _node_index.insert(std::make_pair(n, value));
   795         }
   796       }
   797     }
   798 
   799     void writeArcs() {
   800       _writer_bits::MapStorageBase<Arc>* label = 0;
   801       for (typename ArcMaps::iterator it = _arc_maps.begin();
   802            it != _arc_maps.end(); ++it) {
   803         if (it->first == "label") {
   804           label = it->second;
   805           break;
   806         }
   807       }
   808 
   809       *_os << "@arcs";
   810       if (!_arcs_caption.empty()) {
   811         _writer_bits::writeToken(*_os << ' ', _arcs_caption);
   812       }
   813       *_os << std::endl;
   814 
   815       *_os << '\t' << '\t';
   816       if (label == 0) {
   817         *_os << "label" << '\t';
   818       }
   819       for (typename ArcMaps::iterator it = _arc_maps.begin();
   820            it != _arc_maps.end(); ++it) {
   821         _writer_bits::writeToken(*_os, it->first) << '\t';
   822       }
   823       *_os << std::endl;
   824 
   825       std::vector<Arc> arcs;
   826       for (ArcIt n(_digraph); n != INVALID; ++n) {
   827         arcs.push_back(n);
   828       }
   829 
   830       if (label == 0) {
   831         IdMap<Digraph, Arc> id_map(_digraph);
   832         _writer_bits::MapLess<IdMap<Digraph, Arc> > id_less(id_map);
   833         std::sort(arcs.begin(), arcs.end(), id_less);
   834       } else {
   835         label->sort(arcs);
   836       }
   837 
   838       for (int i = 0; i < static_cast<int>(arcs.size()); ++i) {
   839         Arc a = arcs[i];
   840         _writer_bits::writeToken(*_os, _node_index.
   841                                  find(_digraph.source(a))->second);
   842         *_os << '\t';
   843         _writer_bits::writeToken(*_os, _node_index.
   844                                  find(_digraph.target(a))->second);
   845         *_os << '\t';
   846         if (label == 0) {
   847           std::ostringstream os;
   848           os << _digraph.id(a);
   849           _writer_bits::writeToken(*_os, os.str());
   850           *_os << '\t';
   851           _arc_index.insert(std::make_pair(a, os.str()));
   852         }
   853         for (typename ArcMaps::iterator it = _arc_maps.begin();
   854              it != _arc_maps.end(); ++it) {
   855           std::string value = it->second->get(a);
   856           _writer_bits::writeToken(*_os, value);
   857           if (it->first == "label") {
   858             _arc_index.insert(std::make_pair(a, value));
   859           }
   860           *_os << '\t';
   861         }
   862         *_os << std::endl;
   863       }
   864     }
   865 
   866     void createArcIndex() {
   867       _writer_bits::MapStorageBase<Arc>* label = 0;
   868       for (typename ArcMaps::iterator it = _arc_maps.begin();
   869            it != _arc_maps.end(); ++it) {
   870         if (it->first == "label") {
   871           label = it->second;
   872           break;
   873         }
   874       }
   875 
   876       if (label == 0) {
   877         for (ArcIt a(_digraph); a != INVALID; ++a) {
   878           std::ostringstream os;
   879           os << _digraph.id(a);
   880           _arc_index.insert(std::make_pair(a, os.str()));
   881         }
   882       } else {
   883         for (ArcIt a(_digraph); a != INVALID; ++a) {
   884           std::string value = label->get(a);
   885           _arc_index.insert(std::make_pair(a, value));
   886         }
   887       }
   888     }
   889 
   890     void writeAttributes() {
   891       if (_attributes.empty()) return;
   892       *_os << "@attributes";
   893       if (!_attributes_caption.empty()) {
   894         _writer_bits::writeToken(*_os << ' ', _attributes_caption);
   895       }
   896       *_os << std::endl;
   897       for (typename Attributes::iterator it = _attributes.begin();
   898            it != _attributes.end(); ++it) {
   899         _writer_bits::writeToken(*_os, it->first) << ' ';
   900         _writer_bits::writeToken(*_os, it->second->get());
   901         *_os << std::endl;
   902       }
   903     }
   904 
   905   public:
   906 
   907     /// \name Execution of the writer
   908     /// @{
   909 
   910     /// \brief Start the batch processing
   911     ///
   912     /// This function starts the batch processing.
   913     void run() {
   914       if (!_skip_nodes) {
   915         writeNodes();
   916       } else {
   917         createNodeIndex();
   918       }
   919       if (!_skip_arcs) {
   920         writeArcs();
   921       } else {
   922         createArcIndex();
   923       }
   924       writeAttributes();
   925     }
   926 
   927     /// \brief Give back the stream of the writer
   928     ///
   929     /// Give back the stream of the writer.
   930     std::ostream& ostream() {
   931       return *_os;
   932     }
   933 
   934     /// @}
   935   };
   936 
   937   template <typename Graph>
   938   class GraphWriter;
   939 
   940   /// \brief Return a \ref GraphWriter class
   941   ///
   942   /// This function just returns a \ref GraphWriter class.
   943   /// \relates GraphWriter
   944   template <typename Graph>
   945   GraphWriter<Graph> graphWriter(const Graph& graph,
   946                                  std::ostream& os = std::cout) {
   947     GraphWriter<Graph> tmp(graph, os);
   948     return tmp;
   949   }
   950 
   951   /// \brief Return a \ref GraphWriter class
   952   ///
   953   /// This function just returns a \ref GraphWriter class.
   954   /// \relates GraphWriter
   955   template <typename Graph>
   956   GraphWriter<Graph> graphWriter(const Graph& graph, const std::string& fn) {
   957     GraphWriter<Graph> tmp(graph, fn);
   958     return tmp;
   959   }
   960 
   961   /// \brief Return a \ref GraphWriter class
   962   ///
   963   /// This function just returns a \ref GraphWriter class.
   964   /// \relates GraphWriter
   965   template <typename Graph>
   966   GraphWriter<Graph> graphWriter(const Graph& graph, const char* fn) {
   967     GraphWriter<Graph> tmp(graph, fn);
   968     return tmp;
   969   }
   970 
   971   /// \ingroup lemon_io
   972   ///
   973   /// \brief \ref lgf-format "LGF" writer for directed graphs
   974   ///
   975   /// This utility writes an \ref lgf-format "LGF" file.
   976   ///
   977   /// It can be used almost the same way as \c DigraphWriter.
   978   /// The only difference is that this class can handle edges and
   979   /// edge maps as well as arcs and arc maps.
   980   ///
   981   /// The arc maps are written into the file as two columns, the
   982   /// caption of the columns are the name of the map prefixed with \c
   983   /// '+' and \c '-'. The arcs are written into the \c \@attributes
   984   /// section as a \c '+' or a \c '-' prefix (depends on the direction
   985   /// of the arc) and the label of corresponding edge.
   986   template <typename _Graph>
   987   class GraphWriter {
   988   public:
   989 
   990     typedef _Graph Graph;
   991     TEMPLATE_GRAPH_TYPEDEFS(Graph);
   992 
   993   private:
   994 
   995 
   996     std::ostream* _os;
   997     bool local_os;
   998 
   999     const Graph& _graph;
  1000 
  1001     std::string _nodes_caption;
  1002     std::string _edges_caption;
  1003     std::string _attributes_caption;
  1004 
  1005     typedef std::map<Node, std::string> NodeIndex;
  1006     NodeIndex _node_index;
  1007     typedef std::map<Edge, std::string> EdgeIndex;
  1008     EdgeIndex _edge_index;
  1009 
  1010     typedef std::vector<std::pair<std::string,
  1011       _writer_bits::MapStorageBase<Node>* > > NodeMaps;
  1012     NodeMaps _node_maps;
  1013 
  1014     typedef std::vector<std::pair<std::string,
  1015       _writer_bits::MapStorageBase<Edge>* > >EdgeMaps;
  1016     EdgeMaps _edge_maps;
  1017 
  1018     typedef std::vector<std::pair<std::string,
  1019       _writer_bits::ValueStorageBase*> > Attributes;
  1020     Attributes _attributes;
  1021 
  1022     bool _skip_nodes;
  1023     bool _skip_edges;
  1024 
  1025   public:
  1026 
  1027     /// \brief Constructor
  1028     ///
  1029     /// Construct a directed graph writer, which writes to the given
  1030     /// output stream.
  1031     GraphWriter(const Graph& graph, std::ostream& os = std::cout)
  1032       : _os(&os), local_os(false), _graph(graph),
  1033         _skip_nodes(false), _skip_edges(false) {}
  1034 
  1035     /// \brief Constructor
  1036     ///
  1037     /// Construct a directed graph writer, which writes to the given
  1038     /// output file.
  1039     GraphWriter(const Graph& graph, const std::string& fn)
  1040       : _os(new std::ofstream(fn.c_str())), local_os(true), _graph(graph),
  1041         _skip_nodes(false), _skip_edges(false) {
  1042       if (!(*_os)) {
  1043         delete _os;
  1044         throw IoError("Cannot write file", fn);
  1045       }
  1046     }
  1047 
  1048     /// \brief Constructor
  1049     ///
  1050     /// Construct a directed graph writer, which writes to the given
  1051     /// output file.
  1052     GraphWriter(const Graph& graph, const char* fn)
  1053       : _os(new std::ofstream(fn)), local_os(true), _graph(graph),
  1054         _skip_nodes(false), _skip_edges(false) {
  1055       if (!(*_os)) {
  1056         delete _os;
  1057         throw IoError("Cannot write file", fn);
  1058       }
  1059     }
  1060 
  1061     /// \brief Destructor
  1062     ~GraphWriter() {
  1063       for (typename NodeMaps::iterator it = _node_maps.begin();
  1064            it != _node_maps.end(); ++it) {
  1065         delete it->second;
  1066       }
  1067 
  1068       for (typename EdgeMaps::iterator it = _edge_maps.begin();
  1069            it != _edge_maps.end(); ++it) {
  1070         delete it->second;
  1071       }
  1072 
  1073       for (typename Attributes::iterator it = _attributes.begin();
  1074            it != _attributes.end(); ++it) {
  1075         delete it->second;
  1076       }
  1077 
  1078       if (local_os) {
  1079         delete _os;
  1080       }
  1081     }
  1082 
  1083   private:
  1084 
  1085     friend GraphWriter<Graph> graphWriter<>(const Graph& graph,
  1086                                             std::ostream& os);
  1087     friend GraphWriter<Graph> graphWriter<>(const Graph& graph,
  1088                                             const std::string& fn);
  1089     friend GraphWriter<Graph> graphWriter<>(const Graph& graph,
  1090                                             const char *fn);
  1091 
  1092     GraphWriter(GraphWriter& other)
  1093       : _os(other._os), local_os(other.local_os), _graph(other._graph),
  1094         _skip_nodes(other._skip_nodes), _skip_edges(other._skip_edges) {
  1095 
  1096       other._os = 0;
  1097       other.local_os = false;
  1098 
  1099       _node_index.swap(other._node_index);
  1100       _edge_index.swap(other._edge_index);
  1101 
  1102       _node_maps.swap(other._node_maps);
  1103       _edge_maps.swap(other._edge_maps);
  1104       _attributes.swap(other._attributes);
  1105 
  1106       _nodes_caption = other._nodes_caption;
  1107       _edges_caption = other._edges_caption;
  1108       _attributes_caption = other._attributes_caption;
  1109     }
  1110 
  1111     GraphWriter& operator=(const GraphWriter&);
  1112 
  1113   public:
  1114 
  1115     /// \name Writing rules
  1116     /// @{
  1117 
  1118     /// \brief Node map writing rule
  1119     ///
  1120     /// Add a node map writing rule to the writer.
  1121     template <typename Map>
  1122     GraphWriter& nodeMap(const std::string& caption, const Map& map) {
  1123       checkConcept<concepts::ReadMap<Node, typename Map::Value>, Map>();
  1124       _writer_bits::MapStorageBase<Node>* storage =
  1125         new _writer_bits::MapStorage<Node, Map>(map);
  1126       _node_maps.push_back(std::make_pair(caption, storage));
  1127       return *this;
  1128     }
  1129 
  1130     /// \brief Node map writing rule
  1131     ///
  1132     /// Add a node map writing rule with specialized converter to the
  1133     /// writer.
  1134     template <typename Map, typename Converter>
  1135     GraphWriter& nodeMap(const std::string& caption, const Map& map,
  1136                            const Converter& converter = Converter()) {
  1137       checkConcept<concepts::ReadMap<Node, typename Map::Value>, Map>();
  1138       _writer_bits::MapStorageBase<Node>* storage =
  1139         new _writer_bits::MapStorage<Node, Map, Converter>(map, converter);
  1140       _node_maps.push_back(std::make_pair(caption, storage));
  1141       return *this;
  1142     }
  1143 
  1144     /// \brief Edge map writing rule
  1145     ///
  1146     /// Add an edge map writing rule to the writer.
  1147     template <typename Map>
  1148     GraphWriter& edgeMap(const std::string& caption, const Map& map) {
  1149       checkConcept<concepts::ReadMap<Edge, typename Map::Value>, Map>();
  1150       _writer_bits::MapStorageBase<Edge>* storage =
  1151         new _writer_bits::MapStorage<Edge, Map>(map);
  1152       _edge_maps.push_back(std::make_pair(caption, storage));
  1153       return *this;
  1154     }
  1155 
  1156     /// \brief Edge map writing rule
  1157     ///
  1158     /// Add an edge map writing rule with specialized converter to the
  1159     /// writer.
  1160     template <typename Map, typename Converter>
  1161     GraphWriter& edgeMap(const std::string& caption, const Map& map,
  1162                           const Converter& converter = Converter()) {
  1163       checkConcept<concepts::ReadMap<Edge, typename Map::Value>, Map>();
  1164       _writer_bits::MapStorageBase<Edge>* storage =
  1165         new _writer_bits::MapStorage<Edge, Map, Converter>(map, converter);
  1166       _edge_maps.push_back(std::make_pair(caption, storage));
  1167       return *this;
  1168     }
  1169 
  1170     /// \brief Arc map writing rule
  1171     ///
  1172     /// Add an arc map writing rule to the writer.
  1173     template <typename Map>
  1174     GraphWriter& arcMap(const std::string& caption, const Map& map) {
  1175       checkConcept<concepts::ReadMap<Arc, typename Map::Value>, Map>();
  1176       _writer_bits::MapStorageBase<Edge>* forward_storage =
  1177         new _writer_bits::GraphArcMapStorage<Graph, true, Map>(_graph, map);
  1178       _edge_maps.push_back(std::make_pair('+' + caption, forward_storage));
  1179       _writer_bits::MapStorageBase<Edge>* backward_storage =
  1180         new _writer_bits::GraphArcMapStorage<Graph, false, Map>(_graph, map);
  1181       _edge_maps.push_back(std::make_pair('-' + caption, backward_storage));
  1182       return *this;
  1183     }
  1184 
  1185     /// \brief Arc map writing rule
  1186     ///
  1187     /// Add an arc map writing rule with specialized converter to the
  1188     /// writer.
  1189     template <typename Map, typename Converter>
  1190     GraphWriter& arcMap(const std::string& caption, const Map& map,
  1191                           const Converter& converter = Converter()) {
  1192       checkConcept<concepts::ReadMap<Arc, typename Map::Value>, Map>();
  1193       _writer_bits::MapStorageBase<Edge>* forward_storage =
  1194         new _writer_bits::GraphArcMapStorage<Graph, true, Map, Converter>
  1195         (_graph, map, converter);
  1196       _edge_maps.push_back(std::make_pair('+' + caption, forward_storage));
  1197       _writer_bits::MapStorageBase<Edge>* backward_storage =
  1198         new _writer_bits::GraphArcMapStorage<Graph, false, Map, Converter>
  1199         (_graph, map, converter);
  1200       _edge_maps.push_back(std::make_pair('-' + caption, backward_storage));
  1201       return *this;
  1202     }
  1203 
  1204     /// \brief Attribute writing rule
  1205     ///
  1206     /// Add an attribute writing rule to the writer.
  1207     template <typename Value>
  1208     GraphWriter& attribute(const std::string& caption, const Value& value) {
  1209       _writer_bits::ValueStorageBase* storage =
  1210         new _writer_bits::ValueStorage<Value>(value);
  1211       _attributes.push_back(std::make_pair(caption, storage));
  1212       return *this;
  1213     }
  1214 
  1215     /// \brief Attribute writing rule
  1216     ///
  1217     /// Add an attribute writing rule with specialized converter to the
  1218     /// writer.
  1219     template <typename Value, typename Converter>
  1220     GraphWriter& attribute(const std::string& caption, const Value& value,
  1221                              const Converter& converter = Converter()) {
  1222       _writer_bits::ValueStorageBase* storage =
  1223         new _writer_bits::ValueStorage<Value, Converter>(value, converter);
  1224       _attributes.push_back(std::make_pair(caption, storage));
  1225       return *this;
  1226     }
  1227 
  1228     /// \brief Node writing rule
  1229     ///
  1230     /// Add a node writing rule to the writer.
  1231     GraphWriter& node(const std::string& caption, const Node& node) {
  1232       typedef _writer_bits::MapLookUpConverter<Node> Converter;
  1233       Converter converter(_node_index);
  1234       _writer_bits::ValueStorageBase* storage =
  1235         new _writer_bits::ValueStorage<Node, Converter>(node, converter);
  1236       _attributes.push_back(std::make_pair(caption, storage));
  1237       return *this;
  1238     }
  1239 
  1240     /// \brief Edge writing rule
  1241     ///
  1242     /// Add an edge writing rule to writer.
  1243     GraphWriter& edge(const std::string& caption, const Edge& edge) {
  1244       typedef _writer_bits::MapLookUpConverter<Edge> Converter;
  1245       Converter converter(_edge_index);
  1246       _writer_bits::ValueStorageBase* storage =
  1247         new _writer_bits::ValueStorage<Edge, Converter>(edge, converter);
  1248       _attributes.push_back(std::make_pair(caption, storage));
  1249       return *this;
  1250     }
  1251 
  1252     /// \brief Arc writing rule
  1253     ///
  1254     /// Add an arc writing rule to writer.
  1255     GraphWriter& arc(const std::string& caption, const Arc& arc) {
  1256       typedef _writer_bits::GraphArcLookUpConverter<Graph> Converter;
  1257       Converter converter(_graph, _edge_index);
  1258       _writer_bits::ValueStorageBase* storage =
  1259         new _writer_bits::ValueStorage<Arc, Converter>(arc, converter);
  1260       _attributes.push_back(std::make_pair(caption, storage));
  1261       return *this;
  1262     }
  1263 
  1264     /// \name Section captions
  1265     /// @{
  1266 
  1267     /// \brief Add an additional caption to the \c \@nodes section
  1268     ///
  1269     /// Add an additional caption to the \c \@nodes section.
  1270     GraphWriter& nodes(const std::string& caption) {
  1271       _nodes_caption = caption;
  1272       return *this;
  1273     }
  1274 
  1275     /// \brief Add an additional caption to the \c \@arcs section
  1276     ///
  1277     /// Add an additional caption to the \c \@arcs section.
  1278     GraphWriter& edges(const std::string& caption) {
  1279       _edges_caption = caption;
  1280       return *this;
  1281     }
  1282 
  1283     /// \brief Add an additional caption to the \c \@attributes section
  1284     ///
  1285     /// Add an additional caption to the \c \@attributes section.
  1286     GraphWriter& attributes(const std::string& caption) {
  1287       _attributes_caption = caption;
  1288       return *this;
  1289     }
  1290 
  1291     /// \name Skipping section
  1292     /// @{
  1293 
  1294     /// \brief Skip writing the node set
  1295     ///
  1296     /// The \c \@nodes section will not be written to the stream.
  1297     GraphWriter& skipNodes() {
  1298       LEMON_ASSERT(!_skip_nodes, "Multiple usage of skipNodes() member");
  1299       _skip_nodes = true;
  1300       return *this;
  1301     }
  1302 
  1303     /// \brief Skip writing edge set
  1304     ///
  1305     /// The \c \@edges section will not be written to the stream.
  1306     GraphWriter& skipEdges() {
  1307       LEMON_ASSERT(!_skip_edges, "Multiple usage of skipEdges() member");
  1308       _skip_edges = true;
  1309       return *this;
  1310     }
  1311 
  1312     /// @}
  1313 
  1314   private:
  1315 
  1316     void writeNodes() {
  1317       _writer_bits::MapStorageBase<Node>* label = 0;
  1318       for (typename NodeMaps::iterator it = _node_maps.begin();
  1319            it != _node_maps.end(); ++it) {
  1320         if (it->first == "label") {
  1321           label = it->second;
  1322           break;
  1323         }
  1324       }
  1325 
  1326       *_os << "@nodes";
  1327       if (!_nodes_caption.empty()) {
  1328         _writer_bits::writeToken(*_os << ' ', _nodes_caption);
  1329       }
  1330       *_os << std::endl;
  1331 
  1332       if (label == 0) {
  1333         *_os << "label" << '\t';
  1334       }
  1335       for (typename NodeMaps::iterator it = _node_maps.begin();
  1336            it != _node_maps.end(); ++it) {
  1337         _writer_bits::writeToken(*_os, it->first) << '\t';
  1338       }
  1339       *_os << std::endl;
  1340 
  1341       std::vector<Node> nodes;
  1342       for (NodeIt n(_graph); n != INVALID; ++n) {
  1343         nodes.push_back(n);
  1344       }
  1345 
  1346       if (label == 0) {
  1347         IdMap<Graph, Node> id_map(_graph);
  1348         _writer_bits::MapLess<IdMap<Graph, Node> > id_less(id_map);
  1349         std::sort(nodes.begin(), nodes.end(), id_less);
  1350       } else {
  1351         label->sort(nodes);
  1352       }
  1353 
  1354       for (int i = 0; i < static_cast<int>(nodes.size()); ++i) {
  1355         Node n = nodes[i];
  1356         if (label == 0) {
  1357           std::ostringstream os;
  1358           os << _graph.id(n);
  1359           _writer_bits::writeToken(*_os, os.str());
  1360           *_os << '\t';
  1361           _node_index.insert(std::make_pair(n, os.str()));
  1362         }
  1363         for (typename NodeMaps::iterator it = _node_maps.begin();
  1364              it != _node_maps.end(); ++it) {
  1365           std::string value = it->second->get(n);
  1366           _writer_bits::writeToken(*_os, value);
  1367           if (it->first == "label") {
  1368             _node_index.insert(std::make_pair(n, value));
  1369           }
  1370           *_os << '\t';
  1371         }
  1372         *_os << std::endl;
  1373       }
  1374     }
  1375 
  1376     void createNodeIndex() {
  1377       _writer_bits::MapStorageBase<Node>* label = 0;
  1378       for (typename NodeMaps::iterator it = _node_maps.begin();
  1379            it != _node_maps.end(); ++it) {
  1380         if (it->first == "label") {
  1381           label = it->second;
  1382           break;
  1383         }
  1384       }
  1385 
  1386       if (label == 0) {
  1387         for (NodeIt n(_graph); n != INVALID; ++n) {
  1388           std::ostringstream os;
  1389           os << _graph.id(n);
  1390           _node_index.insert(std::make_pair(n, os.str()));
  1391         }
  1392       } else {
  1393         for (NodeIt n(_graph); n != INVALID; ++n) {
  1394           std::string value = label->get(n);
  1395           _node_index.insert(std::make_pair(n, value));
  1396         }
  1397       }
  1398     }
  1399 
  1400     void writeEdges() {
  1401       _writer_bits::MapStorageBase<Edge>* label = 0;
  1402       for (typename EdgeMaps::iterator it = _edge_maps.begin();
  1403            it != _edge_maps.end(); ++it) {
  1404         if (it->first == "label") {
  1405           label = it->second;
  1406           break;
  1407         }
  1408       }
  1409 
  1410       *_os << "@edges";
  1411       if (!_edges_caption.empty()) {
  1412         _writer_bits::writeToken(*_os << ' ', _edges_caption);
  1413       }
  1414       *_os << std::endl;
  1415 
  1416       *_os << '\t' << '\t';
  1417       if (label == 0) {
  1418         *_os << "label" << '\t';
  1419       }
  1420       for (typename EdgeMaps::iterator it = _edge_maps.begin();
  1421            it != _edge_maps.end(); ++it) {
  1422         _writer_bits::writeToken(*_os, it->first) << '\t';
  1423       }
  1424       *_os << std::endl;
  1425 
  1426       std::vector<Edge> edges;
  1427       for (EdgeIt n(_graph); n != INVALID; ++n) {
  1428         edges.push_back(n);
  1429       }
  1430 
  1431       if (label == 0) {
  1432         IdMap<Graph, Edge> id_map(_graph);
  1433         _writer_bits::MapLess<IdMap<Graph, Edge> > id_less(id_map);
  1434         std::sort(edges.begin(), edges.end(), id_less);
  1435       } else {
  1436         label->sort(edges);
  1437       }
  1438 
  1439       for (int i = 0; i < static_cast<int>(edges.size()); ++i) {
  1440         Edge e = edges[i];
  1441         _writer_bits::writeToken(*_os, _node_index.
  1442                                  find(_graph.u(e))->second);
  1443         *_os << '\t';
  1444         _writer_bits::writeToken(*_os, _node_index.
  1445                                  find(_graph.v(e))->second);
  1446         *_os << '\t';
  1447         if (label == 0) {
  1448           std::ostringstream os;
  1449           os << _graph.id(e);
  1450           _writer_bits::writeToken(*_os, os.str());
  1451           *_os << '\t';
  1452           _edge_index.insert(std::make_pair(e, os.str()));
  1453         }
  1454         for (typename EdgeMaps::iterator it = _edge_maps.begin();
  1455              it != _edge_maps.end(); ++it) {
  1456           std::string value = it->second->get(e);
  1457           _writer_bits::writeToken(*_os, value);
  1458           if (it->first == "label") {
  1459             _edge_index.insert(std::make_pair(e, value));
  1460           }
  1461           *_os << '\t';
  1462         }
  1463         *_os << std::endl;
  1464       }
  1465     }
  1466 
  1467     void createEdgeIndex() {
  1468       _writer_bits::MapStorageBase<Edge>* label = 0;
  1469       for (typename EdgeMaps::iterator it = _edge_maps.begin();
  1470            it != _edge_maps.end(); ++it) {
  1471         if (it->first == "label") {
  1472           label = it->second;
  1473           break;
  1474         }
  1475       }
  1476 
  1477       if (label == 0) {
  1478         for (EdgeIt e(_graph); e != INVALID; ++e) {
  1479           std::ostringstream os;
  1480           os << _graph.id(e);
  1481           _edge_index.insert(std::make_pair(e, os.str()));
  1482         }
  1483       } else {
  1484         for (EdgeIt e(_graph); e != INVALID; ++e) {
  1485           std::string value = label->get(e);
  1486           _edge_index.insert(std::make_pair(e, value));
  1487         }
  1488       }
  1489     }
  1490 
  1491     void writeAttributes() {
  1492       if (_attributes.empty()) return;
  1493       *_os << "@attributes";
  1494       if (!_attributes_caption.empty()) {
  1495         _writer_bits::writeToken(*_os << ' ', _attributes_caption);
  1496       }
  1497       *_os << std::endl;
  1498       for (typename Attributes::iterator it = _attributes.begin();
  1499            it != _attributes.end(); ++it) {
  1500         _writer_bits::writeToken(*_os, it->first) << ' ';
  1501         _writer_bits::writeToken(*_os, it->second->get());
  1502         *_os << std::endl;
  1503       }
  1504     }
  1505 
  1506   public:
  1507 
  1508     /// \name Execution of the writer
  1509     /// @{
  1510 
  1511     /// \brief Start the batch processing
  1512     ///
  1513     /// This function starts the batch processing.
  1514     void run() {
  1515       if (!_skip_nodes) {
  1516         writeNodes();
  1517       } else {
  1518         createNodeIndex();
  1519       }
  1520       if (!_skip_edges) {
  1521         writeEdges();
  1522       } else {
  1523         createEdgeIndex();
  1524       }
  1525       writeAttributes();
  1526     }
  1527 
  1528     /// \brief Give back the stream of the writer
  1529     ///
  1530     /// Give back the stream of the writer
  1531     std::ostream& ostream() {
  1532       return *_os;
  1533     }
  1534 
  1535     /// @}
  1536   };
  1537 
  1538   class SectionWriter;
  1539 
  1540   SectionWriter sectionWriter(std::istream& is);
  1541   SectionWriter sectionWriter(const std::string& fn);
  1542   SectionWriter sectionWriter(const char* fn);
  1543 
  1544   /// \ingroup lemon_io
  1545   ///
  1546   /// \brief Section writer class
  1547   ///
  1548   /// In the \ref lgf-format "LGF" file extra sections can be placed,
  1549   /// which contain any data in arbitrary format. Such sections can be
  1550   /// written with this class. A writing rule can be added to the
  1551   /// class with two different functions. With the \c sectionLines()
  1552   /// function a generator can write the section line-by-line, while
  1553   /// with the \c sectionStream() member the section can be written to
  1554   /// an output stream.
  1555   class SectionWriter {
  1556   private:
  1557 
  1558     std::ostream* _os;
  1559     bool local_os;
  1560 
  1561     typedef std::vector<std::pair<std::string, _writer_bits::Section*> >
  1562     Sections;
  1563 
  1564     Sections _sections;
  1565 
  1566   public:
  1567 
  1568     /// \brief Constructor
  1569     ///
  1570     /// Construct a section writer, which writes to the given output
  1571     /// stream.
  1572     SectionWriter(std::ostream& os)
  1573       : _os(&os), local_os(false) {}
  1574 
  1575     /// \brief Constructor
  1576     ///
  1577     /// Construct a section writer, which writes into the given file.
  1578     SectionWriter(const std::string& fn)
  1579       : _os(new std::ofstream(fn.c_str())), local_os(true) {
  1580       if (!(*_os)) {
  1581         delete _os;
  1582         throw IoError("Cannot write file", fn);
  1583       }
  1584     }
  1585 
  1586     /// \brief Constructor
  1587     ///
  1588     /// Construct a section writer, which writes into the given file.
  1589     SectionWriter(const char* fn)
  1590       : _os(new std::ofstream(fn)), local_os(true) {
  1591       if (!(*_os)) {
  1592         delete _os;
  1593         throw IoError("Cannot write file", fn);
  1594       }
  1595     }
  1596 
  1597     /// \brief Destructor
  1598     ~SectionWriter() {
  1599       for (Sections::iterator it = _sections.begin();
  1600            it != _sections.end(); ++it) {
  1601         delete it->second;
  1602       }
  1603 
  1604       if (local_os) {
  1605         delete _os;
  1606       }
  1607 
  1608     }
  1609 
  1610   private:
  1611 
  1612     friend SectionWriter sectionWriter(std::ostream& os);
  1613     friend SectionWriter sectionWriter(const std::string& fn);
  1614     friend SectionWriter sectionWriter(const char* fn);
  1615 
  1616     SectionWriter(SectionWriter& other)
  1617       : _os(other._os), local_os(other.local_os) {
  1618 
  1619       other._os = 0;
  1620       other.local_os = false;
  1621 
  1622       _sections.swap(other._sections);
  1623     }
  1624 
  1625     SectionWriter& operator=(const SectionWriter&);
  1626 
  1627   public:
  1628 
  1629     /// \name Section writers
  1630     /// @{
  1631 
  1632     /// \brief Add a section writer with line oriented writing
  1633     ///
  1634     /// The first parameter is the type descriptor of the section, the
  1635     /// second is a generator with std::string values. At the writing
  1636     /// process, the returned \c std::string will be written into the
  1637     /// output file until it is an empty string.
  1638     ///
  1639     /// For example, an integer vector is written into a section.
  1640     ///\code
  1641     ///  @numbers
  1642     ///  12 45 23 78
  1643     ///  4 28 38 28
  1644     ///  23 6 16
  1645     ///\endcode
  1646     ///
  1647     /// The generator is implemented as a struct.
  1648     ///\code
  1649     ///  struct NumberSection {
  1650     ///    std::vector<int>::const_iterator _it, _end;
  1651     ///    NumberSection(const std::vector<int>& data)
  1652     ///      : _it(data.begin()), _end(data.end()) {}
  1653     ///    std::string operator()() {
  1654     ///      int rem_in_line = 4;
  1655     ///      std::ostringstream ls;
  1656     ///      while (rem_in_line > 0 && _it != _end) {
  1657     ///        ls << *(_it++) << ' ';
  1658     ///        --rem_in_line;
  1659     ///      }
  1660     ///      return ls.str();
  1661     ///    }
  1662     ///  };
  1663     ///
  1664     ///  // ...
  1665     ///
  1666     ///  writer.sectionLines("numbers", NumberSection(vec));
  1667     ///\endcode
  1668     template <typename Functor>
  1669     SectionWriter& sectionLines(const std::string& type, Functor functor) {
  1670       LEMON_ASSERT(!type.empty(), "Type is empty.");
  1671       _sections.push_back(std::make_pair(type,
  1672         new _writer_bits::LineSection<Functor>(functor)));
  1673       return *this;
  1674     }
  1675 
  1676 
  1677     /// \brief Add a section writer with stream oriented writing
  1678     ///
  1679     /// The first parameter is the type of the section, the second is
  1680     /// a functor, which takes a \c std::ostream& parameter. The
  1681     /// functor writes the section to the output stream.
  1682     /// \warning The last line must be closed with end-line character.
  1683     template <typename Functor>
  1684     SectionWriter& sectionStream(const std::string& type, Functor functor) {
  1685       LEMON_ASSERT(!type.empty(), "Type is empty.");
  1686       _sections.push_back(std::make_pair(type,
  1687          new _writer_bits::StreamSection<Functor>(functor)));
  1688       return *this;
  1689     }
  1690 
  1691     /// @}
  1692 
  1693   public:
  1694 
  1695 
  1696     /// \name Execution of the writer
  1697     /// @{
  1698 
  1699     /// \brief Start the batch processing
  1700     ///
  1701     /// This function starts the batch processing.
  1702     void run() {
  1703 
  1704       LEMON_ASSERT(_os != 0, "This writer is assigned to an other writer");
  1705 
  1706       for (Sections::iterator it = _sections.begin();
  1707            it != _sections.end(); ++it) {
  1708         (*_os) << '@' << it->first << std::endl;
  1709         it->second->process(*_os);
  1710       }
  1711     }
  1712 
  1713     /// \brief Give back the stream of the writer
  1714     ///
  1715     /// Returns the stream of the writer
  1716     std::ostream& ostream() {
  1717       return *_os;
  1718     }
  1719 
  1720     /// @}
  1721 
  1722   };
  1723 
  1724   /// \brief Return a \ref SectionWriter class
  1725   ///
  1726   /// This function just returns a \ref SectionWriter class.
  1727   /// \relates SectionWriter
  1728   inline SectionWriter sectionWriter(std::ostream& os) {
  1729     SectionWriter tmp(os);
  1730     return tmp;
  1731   }
  1732 
  1733   /// \brief Return a \ref SectionWriter class
  1734   ///
  1735   /// This function just returns a \ref SectionWriter class.
  1736   /// \relates SectionWriter
  1737   inline SectionWriter sectionWriter(const std::string& fn) {
  1738     SectionWriter tmp(fn);
  1739     return tmp;
  1740   }
  1741 
  1742   /// \brief Return a \ref SectionWriter class
  1743   ///
  1744   /// This function just returns a \ref SectionWriter class.
  1745   /// \relates SectionWriter
  1746   inline SectionWriter sectionWriter(const char* fn) {
  1747     SectionWriter tmp(fn);
  1748     return tmp;
  1749   }
  1750 }
  1751 
  1752 #endif