COIN-OR::LEMON - Graph Library

source: lemon-1.2/lemon/lgf_writer.h @ 209:765619b7cbb2

Last change on this file since 209:765619b7cbb2 was 209:765619b7cbb2, checked in by Alpar Juttner <alpar@…>, 11 years ago

Apply unify-sources.sh to the source tree

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