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-2013
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/core.h>
37 #include <lemon/maps.h>
38 
39 #include <lemon/concept_check.h>
40 #include <lemon/concepts/maps.h>
41 
42 namespace lemon {
43 
44   namespace _writer_bits {
45 
46     template <typename Value>
47     struct DefaultConverter {
operatorDefaultConverter48       std::string operator()(const Value& value) {
49         std::ostringstream os;
50         os << value;
51         return os.str();
52       }
53     };
54 
55     template <typename T>
56     bool operator<(const T&, const T&) {
57       throw FormatError("Label map is not comparable");
58     }
59 
60     template <typename _Map>
61     class MapLess {
62     public:
63       typedef _Map Map;
64       typedef typename Map::Key Item;
65 
66     private:
67       const Map& _map;
68 
69     public:
MapLess(const Map & map)70       MapLess(const Map& map) : _map(map) {}
71 
operator()72       bool operator()(const Item& left, const Item& right) {
73         return _map[left] < _map[right];
74       }
75     };
76 
77     template <typename _Graph, bool _dir, typename _Map>
78     class GraphArcMapLess {
79     public:
80       typedef _Map Map;
81       typedef _Graph Graph;
82       typedef typename Graph::Edge Item;
83 
84     private:
85       const Graph& _graph;
86       const Map& _map;
87 
88     public:
GraphArcMapLess(const Graph & graph,const Map & map)89       GraphArcMapLess(const Graph& graph, const Map& map)
90         : _graph(graph), _map(map) {}
91 
operator()92       bool operator()(const Item& left, const Item& right) {
93         return _map[_graph.direct(left, _dir)] <
94           _map[_graph.direct(right, _dir)];
95       }
96     };
97 
98     template <typename _Item>
99     class MapStorageBase {
100     public:
101       typedef _Item Item;
102 
103     public:
MapStorageBase()104       MapStorageBase() {}
~MapStorageBase()105       virtual ~MapStorageBase() {}
106 
107       virtual std::string get(const Item& item) = 0;
108       virtual void sort(std::vector<Item>&) = 0;
109     };
110 
111     template <typename _Item, typename _Map,
112               typename _Converter = DefaultConverter<typename _Map::Value> >
113     class MapStorage : public MapStorageBase<_Item> {
114     public:
115       typedef _Map Map;
116       typedef _Converter Converter;
117       typedef _Item Item;
118 
119     private:
120       const Map& _map;
121       Converter _converter;
122 
123     public:
124       MapStorage(const Map& map, const Converter& converter = Converter())
_map(map)125         : _map(map), _converter(converter) {}
~MapStorage()126       virtual ~MapStorage() {}
127 
get(const Item & item)128       virtual std::string get(const Item& item) {
129         return _converter(_map[item]);
130       }
sort(std::vector<Item> & items)131       virtual void sort(std::vector<Item>& items) {
132         MapLess<Map> less(_map);
133         std::sort(items.begin(), items.end(), less);
134       }
135     };
136 
137     template <typename _Graph, bool _dir, typename _Map,
138               typename _Converter = DefaultConverter<typename _Map::Value> >
139     class GraphArcMapStorage : public MapStorageBase<typename _Graph::Edge> {
140     public:
141       typedef _Map Map;
142       typedef _Converter Converter;
143       typedef _Graph Graph;
144       typedef typename Graph::Edge Item;
145       static const bool dir = _dir;
146 
147     private:
148       const Graph& _graph;
149       const Map& _map;
150       Converter _converter;
151 
152     public:
153       GraphArcMapStorage(const Graph& graph, const Map& map,
154                          const Converter& converter = Converter())
_graph(graph)155         : _graph(graph), _map(map), _converter(converter) {}
~GraphArcMapStorage()156       virtual ~GraphArcMapStorage() {}
157 
get(const Item & item)158       virtual std::string get(const Item& item) {
159         return _converter(_map[_graph.direct(item, dir)]);
160       }
sort(std::vector<Item> & items)161       virtual void sort(std::vector<Item>& items) {
162         GraphArcMapLess<Graph, dir, Map> less(_graph, _map);
163         std::sort(items.begin(), items.end(), less);
164       }
165     };
166 
167     class ValueStorageBase {
168     public:
ValueStorageBase()169       ValueStorageBase() {}
~ValueStorageBase()170       virtual ~ValueStorageBase() {}
171 
172       virtual std::string get() = 0;
173     };
174 
175     template <typename _Value, typename _Converter = DefaultConverter<_Value> >
176     class ValueStorage : public ValueStorageBase {
177     public:
178       typedef _Value Value;
179       typedef _Converter Converter;
180 
181     private:
182       const Value& _value;
183       Converter _converter;
184 
185     public:
186       ValueStorage(const Value& value, const Converter& converter = Converter())
_value(value)187         : _value(value), _converter(converter) {}
188 
get()189       virtual std::string get() {
190         return _converter(_value);
191       }
192     };
193 
194     template <typename Value,
195               typename Map = std::map<Value, std::string> >
196     struct MapLookUpConverter {
197       const Map& _map;
198 
MapLookUpConverterMapLookUpConverter199       MapLookUpConverter(const Map& map)
200         : _map(map) {}
201 
operatorMapLookUpConverter202       std::string operator()(const Value& value) {
203         typename Map::const_iterator it = _map.find(value);
204         if (it == _map.end()) {
205           throw FormatError("Item not found");
206         }
207         return it->second;
208       }
209     };
210 
211     template <typename Value,
212               typename Map1 = std::map<Value, std::string>,
213               typename Map2 = std::map<Value, std::string> >
214     struct DoubleMapLookUpConverter {
215       const Map1& _map1;
216       const Map2& _map2;
217 
DoubleMapLookUpConverterDoubleMapLookUpConverter218       DoubleMapLookUpConverter(const Map1& map1, const Map2& map2)
219         : _map1(map1), _map2(map2) {}
220 
operatorDoubleMapLookUpConverter221       std::string operator()(const Value& value) {
222         typename Map1::const_iterator it1 = _map1.find(value);
223         typename Map1::const_iterator it2 = _map2.find(value);
224         if (it1 == _map1.end()) {
225           if (it2 == _map2.end()) {
226             throw FormatError("Item not found");
227           } else {
228             return it2->second;
229           }
230         } else {
231           if (it2 == _map2.end()) {
232             return it1->second;
233           } else {
234             throw FormatError("Item is ambigous");
235           }
236         }
237       }
238     };
239 
240     template <typename Graph>
241     struct GraphArcLookUpConverter {
242       const Graph& _graph;
243       const std::map<typename Graph::Edge, std::string>& _map;
244 
GraphArcLookUpConverterGraphArcLookUpConverter245       GraphArcLookUpConverter(const Graph& graph,
246                               const std::map<typename Graph::Edge,
247                                              std::string>& map)
248         : _graph(graph), _map(map) {}
249 
operatorGraphArcLookUpConverter250       std::string operator()(const typename Graph::Arc& val) {
251         typename std::map<typename Graph::Edge, std::string>
252           ::const_iterator it = _map.find(val);
253         if (it == _map.end()) {
254           throw FormatError("Item not found");
255         }
256         return (_graph.direction(val) ? '+' : '-') + it->second;
257       }
258     };
259 
isWhiteSpace(char c)260     inline bool isWhiteSpace(char c) {
261       return c == ' ' || c == '\t' || c == '\v' ||
262         c == '\n' || c == '\r' || c == '\f';
263     }
264 
isEscaped(char c)265     inline bool isEscaped(char c) {
266       return c == '\\' || c == '\"' || c == '\'' ||
267         c == '\a' || c == '\b';
268     }
269 
writeEscape(std::ostream & os,char c)270     inline static void writeEscape(std::ostream& os, char c) {
271       switch (c) {
272       case '\\':
273         os << "\\\\";
274         return;
275       case '\"':
276         os << "\\\"";
277         return;
278       case '\a':
279         os << "\\a";
280         return;
281       case '\b':
282         os << "\\b";
283         return;
284       case '\f':
285         os << "\\f";
286         return;
287       case '\r':
288         os << "\\r";
289         return;
290       case '\n':
291         os << "\\n";
292         return;
293       case '\t':
294         os << "\\t";
295         return;
296       case '\v':
297         os << "\\v";
298         return;
299       default:
300         if (c < 0x20) {
301           std::ios::fmtflags flags = os.flags();
302           os << '\\' << std::oct << static_cast<int>(c);
303           os.flags(flags);
304         } else {
305           os << c;
306         }
307         return;
308       }
309     }
310 
requireEscape(const std::string & str)311     inline bool requireEscape(const std::string& str) {
312       if (str.empty() || str[0] == '@') return true;
313       std::istringstream is(str);
314       char c;
315       while (is.get(c)) {
316         if (isWhiteSpace(c) || isEscaped(c)) {
317           return true;
318         }
319       }
320       return false;
321     }
322 
writeToken(std::ostream & os,const std::string & str)323     inline std::ostream& writeToken(std::ostream& os, const std::string& str) {
324 
325       if (requireEscape(str)) {
326         os << '\"';
327         for (std::string::const_iterator it = str.begin();
328              it != str.end(); ++it) {
329           writeEscape(os, *it);
330         }
331         os << '\"';
332       } else {
333         os << str;
334       }
335       return os;
336     }
337 
338     class Section {
339     public:
~Section()340       virtual ~Section() {}
341       virtual void process(std::ostream& os) = 0;
342     };
343 
344     template <typename Functor>
345     class LineSection : public Section {
346     private:
347 
348       Functor _functor;
349 
350     public:
351 
LineSection(const Functor & functor)352       LineSection(const Functor& functor) : _functor(functor) {}
~LineSection()353       virtual ~LineSection() {}
354 
process(std::ostream & os)355       virtual void process(std::ostream& os) {
356         std::string line;
357         while (!(line = _functor()).empty()) os << line << std::endl;
358       }
359     };
360 
361     template <typename Functor>
362     class StreamSection : public Section {
363     private:
364 
365       Functor _functor;
366 
367     public:
368 
StreamSection(const Functor & functor)369       StreamSection(const Functor& functor) : _functor(functor) {}
~StreamSection()370       virtual ~StreamSection() {}
371 
process(std::ostream & os)372       virtual void process(std::ostream& os) {
373         _functor(os);
374       }
375     };
376 
377   }
378 
379   template <typename DGR>
380   class DigraphWriter;
381 
382   template <typename TDGR>
383   DigraphWriter<TDGR> digraphWriter(const TDGR& digraph,
384                                    std::ostream& os = std::cout);
385   template <typename TDGR>
386   DigraphWriter<TDGR> digraphWriter(const TDGR& digraph, const std::string& fn);
387 
388   template <typename TDGR>
389   DigraphWriter<TDGR> digraphWriter(const TDGR& digraph, const char* fn);
390 
391 
392   /// \ingroup lemon_io
393   ///
394   /// \brief \ref lgf-format "LGF" writer for directed graphs
395   ///
396   /// This utility writes an \ref lgf-format "LGF" file.
397   ///
398   /// The writing method does a batch processing. The user creates a
399   /// writer object, then various writing rules can be added to the
400   /// writer, and eventually the writing is executed with the \c run()
401   /// member function. A map writing rule can be added to the writer
402   /// with the \c nodeMap() or \c arcMap() members. An optional
403   /// converter parameter can also be added as a standard functor
404   /// converting from the value type of the map to \c std::string. If it
405   /// is set, it will determine how the value type of the map is written to
406   /// the output stream. If the functor is not set, then a default
407   /// conversion will be used. The \c attribute(), \c node() and \c
408   /// arc() functions are used to add attribute writing rules.
409   ///
410   ///\code
411   /// DigraphWriter<DGR>(digraph, std::cout).
412   ///   nodeMap("coordinates", coord_map).
413   ///   nodeMap("size", size).
414   ///   nodeMap("title", title).
415   ///   arcMap("capacity", cap_map).
416   ///   node("source", src).
417   ///   node("target", trg).
418   ///   attribute("caption", caption).
419   ///   run();
420   ///\endcode
421   ///
422   ///
423   /// By default, the writer does not write additional captions to the
424   /// sections, but they can be give as an optional parameter of
425   /// the \c nodes(), \c arcs() or \c
426   /// attributes() functions.
427   ///
428   /// The \c skipNodes() and \c skipArcs() functions forbid the
429   /// writing of the sections. If two arc sections should be written
430   /// to the output, it can be done in two passes, the first pass
431   /// writes the node section and the first arc section, then the
432   /// second pass skips the node section and writes just the arc
433   /// section to the stream. The output stream can be retrieved with
434   /// the \c ostream() function, hence the second pass can append its
435   /// output to the output of the first pass.
436   template <typename DGR>
437   class DigraphWriter {
438   public:
439 
440     typedef DGR Digraph;
441     TEMPLATE_DIGRAPH_TYPEDEFS(DGR);
442 
443   private:
444 
445 
446     std::ostream* _os;
447     bool local_os;
448 
449     const DGR& _digraph;
450 
451     std::string _nodes_caption;
452     std::string _arcs_caption;
453     std::string _attributes_caption;
454 
455     typedef std::map<Node, std::string> NodeIndex;
456     NodeIndex _node_index;
457     typedef std::map<Arc, std::string> ArcIndex;
458     ArcIndex _arc_index;
459 
460     typedef std::vector<std::pair<std::string,
461       _writer_bits::MapStorageBase<Node>* > > NodeMaps;
462     NodeMaps _node_maps;
463 
464     typedef std::vector<std::pair<std::string,
465       _writer_bits::MapStorageBase<Arc>* > >ArcMaps;
466     ArcMaps _arc_maps;
467 
468     typedef std::vector<std::pair<std::string,
469       _writer_bits::ValueStorageBase*> > Attributes;
470     Attributes _attributes;
471 
472     bool _skip_nodes;
473     bool _skip_arcs;
474 
475   public:
476 
477     /// \brief Constructor
478     ///
479     /// Construct a directed graph writer, which writes to the given
480     /// output stream.
481     DigraphWriter(const DGR& digraph, std::ostream& os = std::cout)
482       : _os(&os), local_os(false), _digraph(digraph),
483         _skip_nodes(false), _skip_arcs(false) {}
484 
485     /// \brief Constructor
486     ///
487     /// Construct a directed graph writer, which writes to the given
488     /// output file.
DigraphWriter(const DGR & digraph,const std::string & fn)489     DigraphWriter(const DGR& digraph, const std::string& fn)
490       : _os(new std::ofstream(fn.c_str())), local_os(true), _digraph(digraph),
491         _skip_nodes(false), _skip_arcs(false) {
492       if (!(*_os)) {
493         delete _os;
494         throw IoError("Cannot write file", fn);
495       }
496     }
497 
498     /// \brief Constructor
499     ///
500     /// Construct a directed graph writer, which writes to the given
501     /// output file.
DigraphWriter(const DGR & digraph,const char * fn)502     DigraphWriter(const DGR& digraph, const char* fn)
503       : _os(new std::ofstream(fn)), local_os(true), _digraph(digraph),
504         _skip_nodes(false), _skip_arcs(false) {
505       if (!(*_os)) {
506         delete _os;
507         throw IoError("Cannot write file", fn);
508       }
509     }
510 
511     /// \brief Destructor
~DigraphWriter()512     ~DigraphWriter() {
513       for (typename NodeMaps::iterator it = _node_maps.begin();
514            it != _node_maps.end(); ++it) {
515         delete it->second;
516       }
517 
518       for (typename ArcMaps::iterator it = _arc_maps.begin();
519            it != _arc_maps.end(); ++it) {
520         delete it->second;
521       }
522 
523       for (typename Attributes::iterator it = _attributes.begin();
524            it != _attributes.end(); ++it) {
525         delete it->second;
526       }
527 
528       if (local_os) {
529         delete _os;
530       }
531     }
532 
533   private:
534 
535     template <typename TDGR>
536     friend DigraphWriter<TDGR> digraphWriter(const TDGR& digraph,
537                                              std::ostream& os);
538     template <typename TDGR>
539     friend DigraphWriter<TDGR> digraphWriter(const TDGR& digraph,
540                                              const std::string& fn);
541     template <typename TDGR>
542     friend DigraphWriter<TDGR> digraphWriter(const TDGR& digraph,
543                                              const char *fn);
544 
DigraphWriter(DigraphWriter & other)545     DigraphWriter(DigraphWriter& other)
546       : _os(other._os), local_os(other.local_os), _digraph(other._digraph),
547         _skip_nodes(other._skip_nodes), _skip_arcs(other._skip_arcs) {
548 
549       other._os = 0;
550       other.local_os = false;
551 
552       _node_index.swap(other._node_index);
553       _arc_index.swap(other._arc_index);
554 
555       _node_maps.swap(other._node_maps);
556       _arc_maps.swap(other._arc_maps);
557       _attributes.swap(other._attributes);
558 
559       _nodes_caption = other._nodes_caption;
560       _arcs_caption = other._arcs_caption;
561       _attributes_caption = other._attributes_caption;
562     }
563 
564     DigraphWriter& operator=(const DigraphWriter&);
565 
566   public:
567 
568     /// \name Writing Rules
569     /// @{
570 
571     /// \brief Node map writing rule
572     ///
573     /// Add a node map writing rule to the writer.
574     template <typename Map>
nodeMap(const std::string & caption,const Map & map)575     DigraphWriter& nodeMap(const std::string& caption, const Map& map) {
576       checkConcept<concepts::ReadMap<Node, typename Map::Value>, Map>();
577       _writer_bits::MapStorageBase<Node>* storage =
578         new _writer_bits::MapStorage<Node, Map>(map);
579       _node_maps.push_back(std::make_pair(caption, storage));
580       return *this;
581     }
582 
583     /// \brief Node map writing rule
584     ///
585     /// Add a node map writing rule with specialized converter to the
586     /// writer.
587     template <typename Map, typename Converter>
588     DigraphWriter& nodeMap(const std::string& caption, const Map& map,
589                            const Converter& converter = Converter()) {
590       checkConcept<concepts::ReadMap<Node, typename Map::Value>, Map>();
591       _writer_bits::MapStorageBase<Node>* storage =
592         new _writer_bits::MapStorage<Node, Map, Converter>(map, converter);
593       _node_maps.push_back(std::make_pair(caption, storage));
594       return *this;
595     }
596 
597     /// \brief Arc map writing rule
598     ///
599     /// Add an arc map writing rule to the writer.
600     template <typename Map>
arcMap(const std::string & caption,const Map & map)601     DigraphWriter& arcMap(const std::string& caption, const Map& map) {
602       checkConcept<concepts::ReadMap<Arc, typename Map::Value>, Map>();
603       _writer_bits::MapStorageBase<Arc>* storage =
604         new _writer_bits::MapStorage<Arc, Map>(map);
605       _arc_maps.push_back(std::make_pair(caption, storage));
606       return *this;
607     }
608 
609     /// \brief Arc map writing rule
610     ///
611     /// Add an arc map writing rule with specialized converter to the
612     /// writer.
613     template <typename Map, typename Converter>
614     DigraphWriter& arcMap(const std::string& caption, const Map& map,
615                           const Converter& converter = Converter()) {
616       checkConcept<concepts::ReadMap<Arc, typename Map::Value>, Map>();
617       _writer_bits::MapStorageBase<Arc>* storage =
618         new _writer_bits::MapStorage<Arc, Map, Converter>(map, converter);
619       _arc_maps.push_back(std::make_pair(caption, storage));
620       return *this;
621     }
622 
623     /// \brief Attribute writing rule
624     ///
625     /// Add an attribute writing rule to the writer.
626     template <typename Value>
attribute(const std::string & caption,const Value & value)627     DigraphWriter& attribute(const std::string& caption, const Value& value) {
628       _writer_bits::ValueStorageBase* storage =
629         new _writer_bits::ValueStorage<Value>(value);
630       _attributes.push_back(std::make_pair(caption, storage));
631       return *this;
632     }
633 
634     /// \brief Attribute writing rule
635     ///
636     /// Add an attribute writing rule with specialized converter to the
637     /// writer.
638     template <typename Value, typename Converter>
639     DigraphWriter& attribute(const std::string& caption, const Value& value,
640                              const Converter& converter = Converter()) {
641       _writer_bits::ValueStorageBase* storage =
642         new _writer_bits::ValueStorage<Value, Converter>(value, converter);
643       _attributes.push_back(std::make_pair(caption, storage));
644       return *this;
645     }
646 
647     /// \brief Node writing rule
648     ///
649     /// Add a node writing rule to the writer.
node(const std::string & caption,const Node & node)650     DigraphWriter& node(const std::string& caption, const Node& node) {
651       typedef _writer_bits::MapLookUpConverter<Node> Converter;
652       Converter converter(_node_index);
653       _writer_bits::ValueStorageBase* storage =
654         new _writer_bits::ValueStorage<Node, Converter>(node, converter);
655       _attributes.push_back(std::make_pair(caption, storage));
656       return *this;
657     }
658 
659     /// \brief Arc writing rule
660     ///
661     /// Add an arc writing rule to writer.
arc(const std::string & caption,const Arc & arc)662     DigraphWriter& arc(const std::string& caption, const Arc& arc) {
663       typedef _writer_bits::MapLookUpConverter<Arc> Converter;
664       Converter converter(_arc_index);
665       _writer_bits::ValueStorageBase* storage =
666         new _writer_bits::ValueStorage<Arc, Converter>(arc, converter);
667       _attributes.push_back(std::make_pair(caption, storage));
668       return *this;
669     }
670 
671     /// \name Section Captions
672     /// @{
673 
674     /// \brief Add an additional caption to the \c \@nodes section
675     ///
676     /// Add an additional caption to the \c \@nodes section.
nodes(const std::string & caption)677     DigraphWriter& nodes(const std::string& caption) {
678       _nodes_caption = caption;
679       return *this;
680     }
681 
682     /// \brief Add an additional caption to the \c \@arcs section
683     ///
684     /// Add an additional caption to the \c \@arcs section.
arcs(const std::string & caption)685     DigraphWriter& arcs(const std::string& caption) {
686       _arcs_caption = caption;
687       return *this;
688     }
689 
690     /// \brief Add an additional caption to the \c \@attributes section
691     ///
692     /// Add an additional caption to the \c \@attributes section.
attributes(const std::string & caption)693     DigraphWriter& attributes(const std::string& caption) {
694       _attributes_caption = caption;
695       return *this;
696     }
697 
698     /// \name Skipping Section
699     /// @{
700 
701     /// \brief Skip writing the node set
702     ///
703     /// The \c \@nodes section will not be written to the stream.
skipNodes()704     DigraphWriter& skipNodes() {
705       LEMON_ASSERT(!_skip_nodes, "Multiple usage of skipNodes() member");
706       _skip_nodes = true;
707       return *this;
708     }
709 
710     /// \brief Skip writing arc set
711     ///
712     /// The \c \@arcs section will not be written to the stream.
skipArcs()713     DigraphWriter& skipArcs() {
714       LEMON_ASSERT(!_skip_arcs, "Multiple usage of skipArcs() member");
715       _skip_arcs = true;
716       return *this;
717     }
718 
719     /// @}
720 
721   private:
722 
writeNodes()723     void writeNodes() {
724       _writer_bits::MapStorageBase<Node>* label = 0;
725       for (typename NodeMaps::iterator it = _node_maps.begin();
726            it != _node_maps.end(); ++it) {
727         if (it->first == "label") {
728           label = it->second;
729           break;
730         }
731       }
732 
733       *_os << "@nodes";
734       if (!_nodes_caption.empty()) {
735         _writer_bits::writeToken(*_os << ' ', _nodes_caption);
736       }
737       *_os << std::endl;
738 
739       if (label == 0) {
740         *_os << "label" << '\t';
741       }
742       for (typename NodeMaps::iterator it = _node_maps.begin();
743            it != _node_maps.end(); ++it) {
744         _writer_bits::writeToken(*_os, it->first) << '\t';
745       }
746       *_os << std::endl;
747 
748       std::vector<Node> nodes;
749       for (NodeIt n(_digraph); n != INVALID; ++n) {
750         nodes.push_back(n);
751       }
752 
753       if (label == 0) {
754         IdMap<DGR, Node> id_map(_digraph);
755         _writer_bits::MapLess<IdMap<DGR, Node> > id_less(id_map);
756         std::sort(nodes.begin(), nodes.end(), id_less);
757       } else {
758         label->sort(nodes);
759       }
760 
761       for (int i = 0; i < static_cast<int>(nodes.size()); ++i) {
762         Node n = nodes[i];
763         if (label == 0) {
764           std::ostringstream os;
765           os << _digraph.id(n);
766           _writer_bits::writeToken(*_os, os.str());
767           *_os << '\t';
768           _node_index.insert(std::make_pair(n, os.str()));
769         }
770         for (typename NodeMaps::iterator it = _node_maps.begin();
771              it != _node_maps.end(); ++it) {
772           std::string value = it->second->get(n);
773           _writer_bits::writeToken(*_os, value);
774           if (it->first == "label") {
775             _node_index.insert(std::make_pair(n, value));
776           }
777           *_os << '\t';
778         }
779         *_os << std::endl;
780       }
781     }
782 
createNodeIndex()783     void createNodeIndex() {
784       _writer_bits::MapStorageBase<Node>* label = 0;
785       for (typename NodeMaps::iterator it = _node_maps.begin();
786            it != _node_maps.end(); ++it) {
787         if (it->first == "label") {
788           label = it->second;
789           break;
790         }
791       }
792 
793       if (label == 0) {
794         for (NodeIt n(_digraph); n != INVALID; ++n) {
795           std::ostringstream os;
796           os << _digraph.id(n);
797           _node_index.insert(std::make_pair(n, os.str()));
798         }
799       } else {
800         for (NodeIt n(_digraph); n != INVALID; ++n) {
801           std::string value = label->get(n);
802           _node_index.insert(std::make_pair(n, value));
803         }
804       }
805     }
806 
writeArcs()807     void writeArcs() {
808       _writer_bits::MapStorageBase<Arc>* label = 0;
809       for (typename ArcMaps::iterator it = _arc_maps.begin();
810            it != _arc_maps.end(); ++it) {
811         if (it->first == "label") {
812           label = it->second;
813           break;
814         }
815       }
816 
817       *_os << "@arcs";
818       if (!_arcs_caption.empty()) {
819         _writer_bits::writeToken(*_os << ' ', _arcs_caption);
820       }
821       *_os << std::endl;
822 
823       *_os << '\t' << '\t';
824       if (label == 0) {
825         *_os << "label" << '\t';
826       }
827       for (typename ArcMaps::iterator it = _arc_maps.begin();
828            it != _arc_maps.end(); ++it) {
829         _writer_bits::writeToken(*_os, it->first) << '\t';
830       }
831       *_os << std::endl;
832 
833       std::vector<Arc> arcs;
834       for (ArcIt n(_digraph); n != INVALID; ++n) {
835         arcs.push_back(n);
836       }
837 
838       if (label == 0) {
839         IdMap<DGR, Arc> id_map(_digraph);
840         _writer_bits::MapLess<IdMap<DGR, Arc> > id_less(id_map);
841         std::sort(arcs.begin(), arcs.end(), id_less);
842       } else {
843         label->sort(arcs);
844       }
845 
846       for (int i = 0; i < static_cast<int>(arcs.size()); ++i) {
847         Arc a = arcs[i];
848         _writer_bits::writeToken(*_os, _node_index.
849                                  find(_digraph.source(a))->second);
850         *_os << '\t';
851         _writer_bits::writeToken(*_os, _node_index.
852                                  find(_digraph.target(a))->second);
853         *_os << '\t';
854         if (label == 0) {
855           std::ostringstream os;
856           os << _digraph.id(a);
857           _writer_bits::writeToken(*_os, os.str());
858           *_os << '\t';
859           _arc_index.insert(std::make_pair(a, os.str()));
860         }
861         for (typename ArcMaps::iterator it = _arc_maps.begin();
862              it != _arc_maps.end(); ++it) {
863           std::string value = it->second->get(a);
864           _writer_bits::writeToken(*_os, value);
865           if (it->first == "label") {
866             _arc_index.insert(std::make_pair(a, value));
867           }
868           *_os << '\t';
869         }
870         *_os << std::endl;
871       }
872     }
873 
createArcIndex()874     void createArcIndex() {
875       _writer_bits::MapStorageBase<Arc>* label = 0;
876       for (typename ArcMaps::iterator it = _arc_maps.begin();
877            it != _arc_maps.end(); ++it) {
878         if (it->first == "label") {
879           label = it->second;
880           break;
881         }
882       }
883 
884       if (label == 0) {
885         for (ArcIt a(_digraph); a != INVALID; ++a) {
886           std::ostringstream os;
887           os << _digraph.id(a);
888           _arc_index.insert(std::make_pair(a, os.str()));
889         }
890       } else {
891         for (ArcIt a(_digraph); a != INVALID; ++a) {
892           std::string value = label->get(a);
893           _arc_index.insert(std::make_pair(a, value));
894         }
895       }
896     }
897 
writeAttributes()898     void writeAttributes() {
899       if (_attributes.empty()) return;
900       *_os << "@attributes";
901       if (!_attributes_caption.empty()) {
902         _writer_bits::writeToken(*_os << ' ', _attributes_caption);
903       }
904       *_os << std::endl;
905       for (typename Attributes::iterator it = _attributes.begin();
906            it != _attributes.end(); ++it) {
907         _writer_bits::writeToken(*_os, it->first) << ' ';
908         _writer_bits::writeToken(*_os, it->second->get());
909         *_os << std::endl;
910       }
911     }
912 
913   public:
914 
915     /// \name Execution of the Writer
916     /// @{
917 
918     /// \brief Start the batch processing
919     ///
920     /// This function starts the batch processing.
run()921     void run() {
922       if (!_skip_nodes) {
923         writeNodes();
924       } else {
925         createNodeIndex();
926       }
927       if (!_skip_arcs) {
928         writeArcs();
929       } else {
930         createArcIndex();
931       }
932       writeAttributes();
933     }
934 
935     /// \brief Give back the stream of the writer
936     ///
937     /// Give back the stream of the writer.
ostream()938     std::ostream& ostream() {
939       return *_os;
940     }
941 
942     /// @}
943   };
944 
945   /// \ingroup lemon_io
946   ///
947   /// \brief Return a \ref lemon::DigraphWriter "DigraphWriter" class
948   ///
949   /// This function just returns a \ref lemon::DigraphWriter
950   /// "DigraphWriter" class.
951   ///
952   /// With this function a digraph can be write to a file or output
953   /// stream in \ref lgf-format "LGF" format with several maps and
954   /// attributes. For example, with the following code a network flow
955   /// problem can be written to the standard output, i.e. a digraph
956   /// with a \e capacity map on the arcs and \e source and \e target
957   /// nodes:
958   ///
959   ///\code
960   ///ListDigraph digraph;
961   ///ListDigraph::ArcMap<int> cap(digraph);
962   ///ListDigraph::Node src, trg;
963   ///  // Setting the capacity map and source and target nodes
964   ///digraphWriter(digraph, std::cout).
965   ///  arcMap("capacity", cap).
966   ///  node("source", src).
967   ///  node("target", trg).
968   ///  run();
969   ///\endcode
970   ///
971   /// For a complete documentation, please see the
972   /// \ref lemon::DigraphWriter "DigraphWriter"
973   /// class documentation.
974   /// \warning Don't forget to put the \ref lemon::DigraphWriter::run() "run()"
975   /// to the end of the parameter list.
976   /// \relates DigraphWriter
977   /// \sa digraphWriter(const TDGR& digraph, const std::string& fn)
978   /// \sa digraphWriter(const TDGR& digraph, const char* fn)
979   template <typename TDGR>
digraphWriter(const TDGR & digraph,std::ostream & os)980   DigraphWriter<TDGR> digraphWriter(const TDGR& digraph, std::ostream& os) {
981     DigraphWriter<TDGR> tmp(digraph, os);
982     return tmp;
983   }
984 
985   /// \brief Return a \ref DigraphWriter class
986   ///
987   /// This function just returns a \ref DigraphWriter class.
988   /// \relates DigraphWriter
989   /// \sa digraphWriter(const TDGR& digraph, std::ostream& os)
990   template <typename TDGR>
digraphWriter(const TDGR & digraph,const std::string & fn)991   DigraphWriter<TDGR> digraphWriter(const TDGR& digraph,
992                                     const std::string& fn) {
993     DigraphWriter<TDGR> tmp(digraph, fn);
994     return tmp;
995   }
996 
997   /// \brief Return a \ref DigraphWriter class
998   ///
999   /// This function just returns a \ref DigraphWriter class.
1000   /// \relates DigraphWriter
1001   /// \sa digraphWriter(const TDGR& digraph, std::ostream& os)
1002   template <typename TDGR>
digraphWriter(const TDGR & digraph,const char * fn)1003   DigraphWriter<TDGR> digraphWriter(const TDGR& digraph, const char* fn) {
1004     DigraphWriter<TDGR> tmp(digraph, fn);
1005     return tmp;
1006   }
1007 
1008   template <typename GR>
1009   class GraphWriter;
1010 
1011   template <typename TGR>
1012   GraphWriter<TGR> graphWriter(const TGR& graph, std::ostream& os = std::cout);
1013   template <typename TGR>
1014   GraphWriter<TGR> graphWriter(const TGR& graph, const std::string& fn);
1015   template <typename TGR>
1016   GraphWriter<TGR> graphWriter(const TGR& graph, const char* fn);
1017 
1018   /// \ingroup lemon_io
1019   ///
1020   /// \brief \ref lgf-format "LGF" writer for undirected graphs
1021   ///
1022   /// This utility writes an \ref lgf-format "LGF" file.
1023   ///
1024   /// It can be used almost the same way as \c DigraphWriter.
1025   /// The only difference is that this class can handle edges and
1026   /// edge maps as well as arcs and arc maps.
1027   ///
1028   /// The arc maps are written into the file as two columns, the
1029   /// caption of the columns are the name of the map prefixed with \c
1030   /// '+' and \c '-'. The arcs are written into the \c \@attributes
1031   /// section as a \c '+' or a \c '-' prefix (depends on the direction
1032   /// of the arc) and the label of corresponding edge.
1033   template <typename GR>
1034   class GraphWriter {
1035   public:
1036 
1037     typedef GR Graph;
1038     TEMPLATE_GRAPH_TYPEDEFS(GR);
1039 
1040   private:
1041 
1042 
1043     std::ostream* _os;
1044     bool local_os;
1045 
1046     const GR& _graph;
1047 
1048     std::string _nodes_caption;
1049     std::string _edges_caption;
1050     std::string _attributes_caption;
1051 
1052     typedef std::map<Node, std::string> NodeIndex;
1053     NodeIndex _node_index;
1054     typedef std::map<Edge, std::string> EdgeIndex;
1055     EdgeIndex _edge_index;
1056 
1057     typedef std::vector<std::pair<std::string,
1058       _writer_bits::MapStorageBase<Node>* > > NodeMaps;
1059     NodeMaps _node_maps;
1060 
1061     typedef std::vector<std::pair<std::string,
1062       _writer_bits::MapStorageBase<Edge>* > >EdgeMaps;
1063     EdgeMaps _edge_maps;
1064 
1065     typedef std::vector<std::pair<std::string,
1066       _writer_bits::ValueStorageBase*> > Attributes;
1067     Attributes _attributes;
1068 
1069     bool _skip_nodes;
1070     bool _skip_edges;
1071 
1072   public:
1073 
1074     /// \brief Constructor
1075     ///
1076     /// Construct an undirected graph writer, which writes to the
1077     /// given output stream.
1078     GraphWriter(const GR& graph, std::ostream& os = std::cout)
1079       : _os(&os), local_os(false), _graph(graph),
1080         _skip_nodes(false), _skip_edges(false) {}
1081 
1082     /// \brief Constructor
1083     ///
1084     /// Construct a undirected graph writer, which writes to the given
1085     /// output file.
GraphWriter(const GR & graph,const std::string & fn)1086     GraphWriter(const GR& graph, const std::string& fn)
1087       : _os(new std::ofstream(fn.c_str())), local_os(true), _graph(graph),
1088         _skip_nodes(false), _skip_edges(false) {
1089       if (!(*_os)) {
1090         delete _os;
1091         throw IoError("Cannot write file", fn);
1092       }
1093     }
1094 
1095     /// \brief Constructor
1096     ///
1097     /// Construct a undirected graph writer, which writes to the given
1098     /// output file.
GraphWriter(const GR & graph,const char * fn)1099     GraphWriter(const GR& graph, const char* fn)
1100       : _os(new std::ofstream(fn)), local_os(true), _graph(graph),
1101         _skip_nodes(false), _skip_edges(false) {
1102       if (!(*_os)) {
1103         delete _os;
1104         throw IoError("Cannot write file", fn);
1105       }
1106     }
1107 
1108     /// \brief Destructor
~GraphWriter()1109     ~GraphWriter() {
1110       for (typename NodeMaps::iterator it = _node_maps.begin();
1111            it != _node_maps.end(); ++it) {
1112         delete it->second;
1113       }
1114 
1115       for (typename EdgeMaps::iterator it = _edge_maps.begin();
1116            it != _edge_maps.end(); ++it) {
1117         delete it->second;
1118       }
1119 
1120       for (typename Attributes::iterator it = _attributes.begin();
1121            it != _attributes.end(); ++it) {
1122         delete it->second;
1123       }
1124 
1125       if (local_os) {
1126         delete _os;
1127       }
1128     }
1129 
1130   private:
1131 
1132     template <typename TGR>
1133     friend GraphWriter<TGR> graphWriter(const TGR& graph, std::ostream& os);
1134     template <typename TGR>
1135     friend GraphWriter<TGR> graphWriter(const TGR& graph,
1136                                         const std::string& fn);
1137     template <typename TGR>
1138     friend GraphWriter<TGR> graphWriter(const TGR& graph, const char *fn);
1139 
GraphWriter(GraphWriter & other)1140     GraphWriter(GraphWriter& other)
1141       : _os(other._os), local_os(other.local_os), _graph(other._graph),
1142         _skip_nodes(other._skip_nodes), _skip_edges(other._skip_edges) {
1143 
1144       other._os = 0;
1145       other.local_os = false;
1146 
1147       _node_index.swap(other._node_index);
1148       _edge_index.swap(other._edge_index);
1149 
1150       _node_maps.swap(other._node_maps);
1151       _edge_maps.swap(other._edge_maps);
1152       _attributes.swap(other._attributes);
1153 
1154       _nodes_caption = other._nodes_caption;
1155       _edges_caption = other._edges_caption;
1156       _attributes_caption = other._attributes_caption;
1157     }
1158 
1159     GraphWriter& operator=(const GraphWriter&);
1160 
1161   public:
1162 
1163     /// \name Writing Rules
1164     /// @{
1165 
1166     /// \brief Node map writing rule
1167     ///
1168     /// Add a node map writing rule to the writer.
1169     template <typename Map>
nodeMap(const std::string & caption,const Map & map)1170     GraphWriter& nodeMap(const std::string& caption, const Map& map) {
1171       checkConcept<concepts::ReadMap<Node, typename Map::Value>, Map>();
1172       _writer_bits::MapStorageBase<Node>* storage =
1173         new _writer_bits::MapStorage<Node, Map>(map);
1174       _node_maps.push_back(std::make_pair(caption, storage));
1175       return *this;
1176     }
1177 
1178     /// \brief Node map writing rule
1179     ///
1180     /// Add a node map writing rule with specialized converter to the
1181     /// writer.
1182     template <typename Map, typename Converter>
1183     GraphWriter& nodeMap(const std::string& caption, const Map& map,
1184                            const Converter& converter = Converter()) {
1185       checkConcept<concepts::ReadMap<Node, typename Map::Value>, Map>();
1186       _writer_bits::MapStorageBase<Node>* storage =
1187         new _writer_bits::MapStorage<Node, Map, Converter>(map, converter);
1188       _node_maps.push_back(std::make_pair(caption, storage));
1189       return *this;
1190     }
1191 
1192     /// \brief Edge map writing rule
1193     ///
1194     /// Add an edge map writing rule to the writer.
1195     template <typename Map>
edgeMap(const std::string & caption,const Map & map)1196     GraphWriter& edgeMap(const std::string& caption, const Map& map) {
1197       checkConcept<concepts::ReadMap<Edge, typename Map::Value>, Map>();
1198       _writer_bits::MapStorageBase<Edge>* storage =
1199         new _writer_bits::MapStorage<Edge, Map>(map);
1200       _edge_maps.push_back(std::make_pair(caption, storage));
1201       return *this;
1202     }
1203 
1204     /// \brief Edge map writing rule
1205     ///
1206     /// Add an edge map writing rule with specialized converter to the
1207     /// writer.
1208     template <typename Map, typename Converter>
1209     GraphWriter& edgeMap(const std::string& caption, const Map& map,
1210                           const Converter& converter = Converter()) {
1211       checkConcept<concepts::ReadMap<Edge, typename Map::Value>, Map>();
1212       _writer_bits::MapStorageBase<Edge>* storage =
1213         new _writer_bits::MapStorage<Edge, Map, Converter>(map, converter);
1214       _edge_maps.push_back(std::make_pair(caption, storage));
1215       return *this;
1216     }
1217 
1218     /// \brief Arc map writing rule
1219     ///
1220     /// Add an arc map writing rule to the writer.
1221     template <typename Map>
arcMap(const std::string & caption,const Map & map)1222     GraphWriter& arcMap(const std::string& caption, const Map& map) {
1223       checkConcept<concepts::ReadMap<Arc, typename Map::Value>, Map>();
1224       _writer_bits::MapStorageBase<Edge>* forward_storage =
1225         new _writer_bits::GraphArcMapStorage<GR, true, Map>(_graph, map);
1226       _edge_maps.push_back(std::make_pair('+' + caption, forward_storage));
1227       _writer_bits::MapStorageBase<Edge>* backward_storage =
1228         new _writer_bits::GraphArcMapStorage<GR, false, Map>(_graph, map);
1229       _edge_maps.push_back(std::make_pair('-' + caption, backward_storage));
1230       return *this;
1231     }
1232 
1233     /// \brief Arc map writing rule
1234     ///
1235     /// Add an arc map writing rule with specialized converter to the
1236     /// writer.
1237     template <typename Map, typename Converter>
1238     GraphWriter& arcMap(const std::string& caption, const Map& map,
1239                           const Converter& converter = Converter()) {
1240       checkConcept<concepts::ReadMap<Arc, typename Map::Value>, Map>();
1241       _writer_bits::MapStorageBase<Edge>* forward_storage =
1242         new _writer_bits::GraphArcMapStorage<GR, true, Map, Converter>
1243         (_graph, map, converter);
1244       _edge_maps.push_back(std::make_pair('+' + caption, forward_storage));
1245       _writer_bits::MapStorageBase<Edge>* backward_storage =
1246         new _writer_bits::GraphArcMapStorage<GR, false, Map, Converter>
1247         (_graph, map, converter);
1248       _edge_maps.push_back(std::make_pair('-' + caption, backward_storage));
1249       return *this;
1250     }
1251 
1252     /// \brief Attribute writing rule
1253     ///
1254     /// Add an attribute writing rule to the writer.
1255     template <typename Value>
attribute(const std::string & caption,const Value & value)1256     GraphWriter& attribute(const std::string& caption, const Value& value) {
1257       _writer_bits::ValueStorageBase* storage =
1258         new _writer_bits::ValueStorage<Value>(value);
1259       _attributes.push_back(std::make_pair(caption, storage));
1260       return *this;
1261     }
1262 
1263     /// \brief Attribute writing rule
1264     ///
1265     /// Add an attribute writing rule with specialized converter to the
1266     /// writer.
1267     template <typename Value, typename Converter>
1268     GraphWriter& attribute(const std::string& caption, const Value& value,
1269                              const Converter& converter = Converter()) {
1270       _writer_bits::ValueStorageBase* storage =
1271         new _writer_bits::ValueStorage<Value, Converter>(value, converter);
1272       _attributes.push_back(std::make_pair(caption, storage));
1273       return *this;
1274     }
1275 
1276     /// \brief Node writing rule
1277     ///
1278     /// Add a node writing rule to the writer.
node(const std::string & caption,const Node & node)1279     GraphWriter& node(const std::string& caption, const Node& node) {
1280       typedef _writer_bits::MapLookUpConverter<Node> Converter;
1281       Converter converter(_node_index);
1282       _writer_bits::ValueStorageBase* storage =
1283         new _writer_bits::ValueStorage<Node, Converter>(node, converter);
1284       _attributes.push_back(std::make_pair(caption, storage));
1285       return *this;
1286     }
1287 
1288     /// \brief Edge writing rule
1289     ///
1290     /// Add an edge writing rule to writer.
edge(const std::string & caption,const Edge & edge)1291     GraphWriter& edge(const std::string& caption, const Edge& edge) {
1292       typedef _writer_bits::MapLookUpConverter<Edge> Converter;
1293       Converter converter(_edge_index);
1294       _writer_bits::ValueStorageBase* storage =
1295         new _writer_bits::ValueStorage<Edge, Converter>(edge, converter);
1296       _attributes.push_back(std::make_pair(caption, storage));
1297       return *this;
1298     }
1299 
1300     /// \brief Arc writing rule
1301     ///
1302     /// Add an arc writing rule to writer.
arc(const std::string & caption,const Arc & arc)1303     GraphWriter& arc(const std::string& caption, const Arc& arc) {
1304       typedef _writer_bits::GraphArcLookUpConverter<GR> Converter;
1305       Converter converter(_graph, _edge_index);
1306       _writer_bits::ValueStorageBase* storage =
1307         new _writer_bits::ValueStorage<Arc, Converter>(arc, converter);
1308       _attributes.push_back(std::make_pair(caption, storage));
1309       return *this;
1310     }
1311 
1312     /// \name Section Captions
1313     /// @{
1314 
1315     /// \brief Add an additional caption to the \c \@nodes section
1316     ///
1317     /// Add an additional caption to the \c \@nodes section.
nodes(const std::string & caption)1318     GraphWriter& nodes(const std::string& caption) {
1319       _nodes_caption = caption;
1320       return *this;
1321     }
1322 
1323     /// \brief Add an additional caption to the \c \@edges section
1324     ///
1325     /// Add an additional caption to the \c \@edges section.
edges(const std::string & caption)1326     GraphWriter& edges(const std::string& caption) {
1327       _edges_caption = caption;
1328       return *this;
1329     }
1330 
1331     /// \brief Add an additional caption to the \c \@attributes section
1332     ///
1333     /// Add an additional caption to the \c \@attributes section.
attributes(const std::string & caption)1334     GraphWriter& attributes(const std::string& caption) {
1335       _attributes_caption = caption;
1336       return *this;
1337     }
1338 
1339     /// \name Skipping Section
1340     /// @{
1341 
1342     /// \brief Skip writing the node set
1343     ///
1344     /// The \c \@nodes section will not be written to the stream.
skipNodes()1345     GraphWriter& skipNodes() {
1346       LEMON_ASSERT(!_skip_nodes, "Multiple usage of skipNodes() member");
1347       _skip_nodes = true;
1348       return *this;
1349     }
1350 
1351     /// \brief Skip writing edge set
1352     ///
1353     /// The \c \@edges section will not be written to the stream.
skipEdges()1354     GraphWriter& skipEdges() {
1355       LEMON_ASSERT(!_skip_edges, "Multiple usage of skipEdges() member");
1356       _skip_edges = true;
1357       return *this;
1358     }
1359 
1360     /// @}
1361 
1362   private:
1363 
writeNodes()1364     void writeNodes() {
1365       _writer_bits::MapStorageBase<Node>* label = 0;
1366       for (typename NodeMaps::iterator it = _node_maps.begin();
1367            it != _node_maps.end(); ++it) {
1368         if (it->first == "label") {
1369           label = it->second;
1370           break;
1371         }
1372       }
1373 
1374       *_os << "@nodes";
1375       if (!_nodes_caption.empty()) {
1376         _writer_bits::writeToken(*_os << ' ', _nodes_caption);
1377       }
1378       *_os << std::endl;
1379 
1380       if (label == 0) {
1381         *_os << "label" << '\t';
1382       }
1383       for (typename NodeMaps::iterator it = _node_maps.begin();
1384            it != _node_maps.end(); ++it) {
1385         _writer_bits::writeToken(*_os, it->first) << '\t';
1386       }
1387       *_os << std::endl;
1388 
1389       std::vector<Node> nodes;
1390       for (NodeIt n(_graph); n != INVALID; ++n) {
1391         nodes.push_back(n);
1392       }
1393 
1394       if (label == 0) {
1395         IdMap<GR, Node> id_map(_graph);
1396         _writer_bits::MapLess<IdMap<GR, Node> > id_less(id_map);
1397         std::sort(nodes.begin(), nodes.end(), id_less);
1398       } else {
1399         label->sort(nodes);
1400       }
1401 
1402       for (int i = 0; i < static_cast<int>(nodes.size()); ++i) {
1403         Node n = nodes[i];
1404         if (label == 0) {
1405           std::ostringstream os;
1406           os << _graph.id(n);
1407           _writer_bits::writeToken(*_os, os.str());
1408           *_os << '\t';
1409           _node_index.insert(std::make_pair(n, os.str()));
1410         }
1411         for (typename NodeMaps::iterator it = _node_maps.begin();
1412              it != _node_maps.end(); ++it) {
1413           std::string value = it->second->get(n);
1414           _writer_bits::writeToken(*_os, value);
1415           if (it->first == "label") {
1416             _node_index.insert(std::make_pair(n, value));
1417           }
1418           *_os << '\t';
1419         }
1420         *_os << std::endl;
1421       }
1422     }
1423 
createNodeIndex()1424     void createNodeIndex() {
1425       _writer_bits::MapStorageBase<Node>* label = 0;
1426       for (typename NodeMaps::iterator it = _node_maps.begin();
1427            it != _node_maps.end(); ++it) {
1428         if (it->first == "label") {
1429           label = it->second;
1430           break;
1431         }
1432       }
1433 
1434       if (label == 0) {
1435         for (NodeIt n(_graph); n != INVALID; ++n) {
1436           std::ostringstream os;
1437           os << _graph.id(n);
1438           _node_index.insert(std::make_pair(n, os.str()));
1439         }
1440       } else {
1441         for (NodeIt n(_graph); n != INVALID; ++n) {
1442           std::string value = label->get(n);
1443           _node_index.insert(std::make_pair(n, value));
1444         }
1445       }
1446     }
1447 
writeEdges()1448     void writeEdges() {
1449       _writer_bits::MapStorageBase<Edge>* label = 0;
1450       for (typename EdgeMaps::iterator it = _edge_maps.begin();
1451            it != _edge_maps.end(); ++it) {
1452         if (it->first == "label") {
1453           label = it->second;
1454           break;
1455         }
1456       }
1457 
1458       *_os << "@edges";
1459       if (!_edges_caption.empty()) {
1460         _writer_bits::writeToken(*_os << ' ', _edges_caption);
1461       }
1462       *_os << std::endl;
1463 
1464       *_os << '\t' << '\t';
1465       if (label == 0) {
1466         *_os << "label" << '\t';
1467       }
1468       for (typename EdgeMaps::iterator it = _edge_maps.begin();
1469            it != _edge_maps.end(); ++it) {
1470         _writer_bits::writeToken(*_os, it->first) << '\t';
1471       }
1472       *_os << std::endl;
1473 
1474       std::vector<Edge> edges;
1475       for (EdgeIt n(_graph); n != INVALID; ++n) {
1476         edges.push_back(n);
1477       }
1478 
1479       if (label == 0) {
1480         IdMap<GR, Edge> id_map(_graph);
1481         _writer_bits::MapLess<IdMap<GR, Edge> > id_less(id_map);
1482         std::sort(edges.begin(), edges.end(), id_less);
1483       } else {
1484         label->sort(edges);
1485       }
1486 
1487       for (int i = 0; i < static_cast<int>(edges.size()); ++i) {
1488         Edge e = edges[i];
1489         _writer_bits::writeToken(*_os, _node_index.
1490                                  find(_graph.u(e))->second);
1491         *_os << '\t';
1492         _writer_bits::writeToken(*_os, _node_index.
1493                                  find(_graph.v(e))->second);
1494         *_os << '\t';
1495         if (label == 0) {
1496           std::ostringstream os;
1497           os << _graph.id(e);
1498           _writer_bits::writeToken(*_os, os.str());
1499           *_os << '\t';
1500           _edge_index.insert(std::make_pair(e, os.str()));
1501         }
1502         for (typename EdgeMaps::iterator it = _edge_maps.begin();
1503              it != _edge_maps.end(); ++it) {
1504           std::string value = it->second->get(e);
1505           _writer_bits::writeToken(*_os, value);
1506           if (it->first == "label") {
1507             _edge_index.insert(std::make_pair(e, value));
1508           }
1509           *_os << '\t';
1510         }
1511         *_os << std::endl;
1512       }
1513     }
1514 
createEdgeIndex()1515     void createEdgeIndex() {
1516       _writer_bits::MapStorageBase<Edge>* label = 0;
1517       for (typename EdgeMaps::iterator it = _edge_maps.begin();
1518            it != _edge_maps.end(); ++it) {
1519         if (it->first == "label") {
1520           label = it->second;
1521           break;
1522         }
1523       }
1524 
1525       if (label == 0) {
1526         for (EdgeIt e(_graph); e != INVALID; ++e) {
1527           std::ostringstream os;
1528           os << _graph.id(e);
1529           _edge_index.insert(std::make_pair(e, os.str()));
1530         }
1531       } else {
1532         for (EdgeIt e(_graph); e != INVALID; ++e) {
1533           std::string value = label->get(e);
1534           _edge_index.insert(std::make_pair(e, value));
1535         }
1536       }
1537     }
1538 
writeAttributes()1539     void writeAttributes() {
1540       if (_attributes.empty()) return;
1541       *_os << "@attributes";
1542       if (!_attributes_caption.empty()) {
1543         _writer_bits::writeToken(*_os << ' ', _attributes_caption);
1544       }
1545       *_os << std::endl;
1546       for (typename Attributes::iterator it = _attributes.begin();
1547            it != _attributes.end(); ++it) {
1548         _writer_bits::writeToken(*_os, it->first) << ' ';
1549         _writer_bits::writeToken(*_os, it->second->get());
1550         *_os << std::endl;
1551       }
1552     }
1553 
1554   public:
1555 
1556     /// \name Execution of the Writer
1557     /// @{
1558 
1559     /// \brief Start the batch processing
1560     ///
1561     /// This function starts the batch processing.
run()1562     void run() {
1563       if (!_skip_nodes) {
1564         writeNodes();
1565       } else {
1566         createNodeIndex();
1567       }
1568       if (!_skip_edges) {
1569         writeEdges();
1570       } else {
1571         createEdgeIndex();
1572       }
1573       writeAttributes();
1574     }
1575 
1576     /// \brief Give back the stream of the writer
1577     ///
1578     /// Give back the stream of the writer
ostream()1579     std::ostream& ostream() {
1580       return *_os;
1581     }
1582 
1583     /// @}
1584   };
1585 
1586   /// \ingroup lemon_io
1587   ///
1588   /// \brief Return a \ref lemon::GraphWriter "GraphWriter" class
1589   ///
1590   /// This function just returns a \ref lemon::GraphWriter "GraphWriter" class.
1591   ///
1592   /// With this function a graph can be write to a file or output
1593   /// stream in \ref lgf-format "LGF" format with several maps and
1594   /// attributes. For example, with the following code a weighted
1595   /// matching problem can be written to the standard output, i.e. a
1596   /// graph with a \e weight map on the edges:
1597   ///
1598   ///\code
1599   ///ListGraph graph;
1600   ///ListGraph::EdgeMap<int> weight(graph);
1601   ///  // Setting the weight map
1602   ///graphWriter(graph, std::cout).
1603   ///  edgeMap("weight", weight).
1604   ///  run();
1605   ///\endcode
1606   ///
1607   /// For a complete documentation, please see the
1608   /// \ref lemon::GraphWriter "GraphWriter"
1609   /// class documentation.
1610   /// \warning Don't forget to put the \ref lemon::GraphWriter::run() "run()"
1611   /// to the end of the parameter list.
1612   /// \relates GraphWriter
1613   /// \sa graphWriter(const TGR& graph, const std::string& fn)
1614   /// \sa graphWriter(const TGR& graph, const char* fn)
1615   template <typename TGR>
graphWriter(const TGR & graph,std::ostream & os)1616   GraphWriter<TGR> graphWriter(const TGR& graph, std::ostream& os) {
1617     GraphWriter<TGR> tmp(graph, os);
1618     return tmp;
1619   }
1620 
1621   /// \brief Return a \ref GraphWriter class
1622   ///
1623   /// This function just returns a \ref GraphWriter class.
1624   /// \relates GraphWriter
1625   /// \sa graphWriter(const TGR& graph, std::ostream& os)
1626   template <typename TGR>
graphWriter(const TGR & graph,const std::string & fn)1627   GraphWriter<TGR> graphWriter(const TGR& graph, const std::string& fn) {
1628     GraphWriter<TGR> tmp(graph, fn);
1629     return tmp;
1630   }
1631 
1632   /// \brief Return a \ref GraphWriter class
1633   ///
1634   /// This function just returns a \ref GraphWriter class.
1635   /// \relates GraphWriter
1636   /// \sa graphWriter(const TGR& graph, std::ostream& os)
1637   template <typename TGR>
graphWriter(const TGR & graph,const char * fn)1638   GraphWriter<TGR> graphWriter(const TGR& graph, const char* fn) {
1639     GraphWriter<TGR> tmp(graph, fn);
1640     return tmp;
1641   }
1642 
1643   template <typename BGR>
1644   class BpGraphWriter;
1645 
1646   template <typename TBGR>
1647   BpGraphWriter<TBGR> bpGraphWriter(const TBGR& graph,
1648                                     std::ostream& os = std::cout);
1649   template <typename TBGR>
1650   BpGraphWriter<TBGR> bpGraphWriter(const TBGR& graph, const std::string& fn);
1651   template <typename TBGR>
1652   BpGraphWriter<TBGR> bpGraphWriter(const TBGR& graph, const char* fn);
1653 
1654   /// \ingroup lemon_io
1655   ///
1656   /// \brief \ref lgf-format "LGF" writer for undirected bipartite graphs
1657   ///
1658   /// This utility writes an \ref lgf-format "LGF" file.
1659   ///
1660   /// It can be used almost the same way as \c GraphWriter, but it
1661   /// reads the red and blue nodes from separate sections, and these
1662   /// sections can contain different set of maps.
1663   ///
1664   /// The red and blue node maps are written to the corresponding
1665   /// sections. The node maps are written to both of these sections
1666   /// with the same map name.
1667   template <typename BGR>
1668   class BpGraphWriter {
1669   public:
1670 
1671     typedef BGR BpGraph;
1672     TEMPLATE_BPGRAPH_TYPEDEFS(BGR);
1673 
1674   private:
1675 
1676 
1677     std::ostream* _os;
1678     bool local_os;
1679 
1680     const BGR& _graph;
1681 
1682     std::string _nodes_caption;
1683     std::string _edges_caption;
1684     std::string _attributes_caption;
1685 
1686     typedef std::map<Node, std::string> RedNodeIndex;
1687     RedNodeIndex _red_node_index;
1688     typedef std::map<Node, std::string> BlueNodeIndex;
1689     BlueNodeIndex _blue_node_index;
1690     typedef std::map<Edge, std::string> EdgeIndex;
1691     EdgeIndex _edge_index;
1692 
1693     typedef std::vector<std::pair<std::string,
1694       _writer_bits::MapStorageBase<RedNode>* > > RedNodeMaps;
1695     RedNodeMaps _red_node_maps;
1696     typedef std::vector<std::pair<std::string,
1697       _writer_bits::MapStorageBase<BlueNode>* > > BlueNodeMaps;
1698     BlueNodeMaps _blue_node_maps;
1699 
1700     typedef std::vector<std::pair<std::string,
1701       _writer_bits::MapStorageBase<Edge>* > >EdgeMaps;
1702     EdgeMaps _edge_maps;
1703 
1704     typedef std::vector<std::pair<std::string,
1705       _writer_bits::ValueStorageBase*> > Attributes;
1706     Attributes _attributes;
1707 
1708     bool _skip_nodes;
1709     bool _skip_edges;
1710 
1711   public:
1712 
1713     /// \brief Constructor
1714     ///
1715     /// Construct a bipartite graph writer, which writes to the given
1716     /// output stream.
1717     BpGraphWriter(const BGR& graph, std::ostream& os = std::cout)
1718       : _os(&os), local_os(false), _graph(graph),
1719         _skip_nodes(false), _skip_edges(false) {}
1720 
1721     /// \brief Constructor
1722     ///
1723     /// Construct a bipartite graph writer, which writes to the given
1724     /// output file.
BpGraphWriter(const BGR & graph,const std::string & fn)1725     BpGraphWriter(const BGR& graph, const std::string& fn)
1726       : _os(new std::ofstream(fn.c_str())), local_os(true), _graph(graph),
1727         _skip_nodes(false), _skip_edges(false) {
1728       if (!(*_os)) {
1729         delete _os;
1730         throw IoError("Cannot write file", fn);
1731       }
1732     }
1733 
1734     /// \brief Constructor
1735     ///
1736     /// Construct a bipartite graph writer, which writes to the given
1737     /// output file.
BpGraphWriter(const BGR & graph,const char * fn)1738     BpGraphWriter(const BGR& graph, const char* fn)
1739       : _os(new std::ofstream(fn)), local_os(true), _graph(graph),
1740         _skip_nodes(false), _skip_edges(false) {
1741       if (!(*_os)) {
1742         delete _os;
1743         throw IoError("Cannot write file", fn);
1744       }
1745     }
1746 
1747     /// \brief Destructor
~BpGraphWriter()1748     ~BpGraphWriter() {
1749       for (typename RedNodeMaps::iterator it = _red_node_maps.begin();
1750            it != _red_node_maps.end(); ++it) {
1751         delete it->second;
1752       }
1753 
1754       for (typename BlueNodeMaps::iterator it = _blue_node_maps.begin();
1755            it != _blue_node_maps.end(); ++it) {
1756         delete it->second;
1757       }
1758 
1759       for (typename EdgeMaps::iterator it = _edge_maps.begin();
1760            it != _edge_maps.end(); ++it) {
1761         delete it->second;
1762       }
1763 
1764       for (typename Attributes::iterator it = _attributes.begin();
1765            it != _attributes.end(); ++it) {
1766         delete it->second;
1767       }
1768 
1769       if (local_os) {
1770         delete _os;
1771       }
1772     }
1773 
1774   private:
1775 
1776     template <typename TBGR>
1777     friend BpGraphWriter<TBGR> bpGraphWriter(const TBGR& graph,
1778                                              std::ostream& os);
1779     template <typename TBGR>
1780     friend BpGraphWriter<TBGR> bpGraphWriter(const TBGR& graph,
1781                                              const std::string& fn);
1782     template <typename TBGR>
1783     friend BpGraphWriter<TBGR> bpGraphWriter(const TBGR& graph, const char *fn);
1784 
BpGraphWriter(BpGraphWriter & other)1785     BpGraphWriter(BpGraphWriter& other)
1786       : _os(other._os), local_os(other.local_os), _graph(other._graph),
1787         _skip_nodes(other._skip_nodes), _skip_edges(other._skip_edges) {
1788 
1789       other._os = 0;
1790       other.local_os = false;
1791 
1792       _red_node_index.swap(other._red_node_index);
1793       _blue_node_index.swap(other._blue_node_index);
1794       _edge_index.swap(other._edge_index);
1795 
1796       _red_node_maps.swap(other._red_node_maps);
1797       _blue_node_maps.swap(other._blue_node_maps);
1798       _edge_maps.swap(other._edge_maps);
1799       _attributes.swap(other._attributes);
1800 
1801       _nodes_caption = other._nodes_caption;
1802       _edges_caption = other._edges_caption;
1803       _attributes_caption = other._attributes_caption;
1804     }
1805 
1806     BpGraphWriter& operator=(const BpGraphWriter&);
1807 
1808   public:
1809 
1810     /// \name Writing Rules
1811     /// @{
1812 
1813     /// \brief Node map writing rule
1814     ///
1815     /// Add a node map writing rule to the writer.
1816     template <typename Map>
nodeMap(const std::string & caption,const Map & map)1817     BpGraphWriter& nodeMap(const std::string& caption, const Map& map) {
1818       checkConcept<concepts::ReadMap<Node, typename Map::Value>, Map>();
1819       _writer_bits::MapStorageBase<RedNode>* red_storage =
1820         new _writer_bits::MapStorage<RedNode, Map>(map);
1821       _red_node_maps.push_back(std::make_pair(caption, red_storage));
1822       _writer_bits::MapStorageBase<BlueNode>* blue_storage =
1823         new _writer_bits::MapStorage<BlueNode, Map>(map);
1824       _blue_node_maps.push_back(std::make_pair(caption, blue_storage));
1825       return *this;
1826     }
1827 
1828     /// \brief Node map writing rule
1829     ///
1830     /// Add a node map writing rule with specialized converter to the
1831     /// writer.
1832     template <typename Map, typename Converter>
1833     BpGraphWriter& nodeMap(const std::string& caption, const Map& map,
1834                            const Converter& converter = Converter()) {
1835       checkConcept<concepts::ReadMap<Node, typename Map::Value>, Map>();
1836       _writer_bits::MapStorageBase<RedNode>* red_storage =
1837         new _writer_bits::MapStorage<RedNode, Map, Converter>(map, converter);
1838       _red_node_maps.push_back(std::make_pair(caption, red_storage));
1839       _writer_bits::MapStorageBase<BlueNode>* blue_storage =
1840         new _writer_bits::MapStorage<BlueNode, Map, Converter>(map, converter);
1841       _blue_node_maps.push_back(std::make_pair(caption, blue_storage));
1842       return *this;
1843     }
1844 
1845     /// \brief Red node map writing rule
1846     ///
1847     /// Add a red node map writing rule to the writer.
1848     template <typename Map>
redNodeMap(const std::string & caption,const Map & map)1849     BpGraphWriter& redNodeMap(const std::string& caption, const Map& map) {
1850       checkConcept<concepts::ReadMap<RedNode, typename Map::Value>, Map>();
1851       _writer_bits::MapStorageBase<RedNode>* storage =
1852         new _writer_bits::MapStorage<RedNode, Map>(map);
1853       _red_node_maps.push_back(std::make_pair(caption, storage));
1854       return *this;
1855     }
1856 
1857     /// \brief Red node map writing rule
1858     ///
1859     /// Add a red node map writing rule with specialized converter to the
1860     /// writer.
1861     template <typename Map, typename Converter>
1862     BpGraphWriter& redNodeMap(const std::string& caption, const Map& map,
1863                               const Converter& converter = Converter()) {
1864       checkConcept<concepts::ReadMap<RedNode, typename Map::Value>, Map>();
1865       _writer_bits::MapStorageBase<RedNode>* storage =
1866         new _writer_bits::MapStorage<RedNode, Map, Converter>(map, converter);
1867       _red_node_maps.push_back(std::make_pair(caption, storage));
1868       return *this;
1869     }
1870 
1871     /// \brief Blue node map writing rule
1872     ///
1873     /// Add a blue node map writing rule to the writer.
1874     template <typename Map>
blueNodeMap(const std::string & caption,const Map & map)1875     BpGraphWriter& blueNodeMap(const std::string& caption, const Map& map) {
1876       checkConcept<concepts::ReadMap<BlueNode, typename Map::Value>, Map>();
1877       _writer_bits::MapStorageBase<BlueNode>* storage =
1878         new _writer_bits::MapStorage<BlueNode, Map>(map);
1879       _blue_node_maps.push_back(std::make_pair(caption, storage));
1880       return *this;
1881     }
1882 
1883     /// \brief Blue node map writing rule
1884     ///
1885     /// Add a blue node map writing rule with specialized converter to the
1886     /// writer.
1887     template <typename Map, typename Converter>
1888     BpGraphWriter& blueNodeMap(const std::string& caption, const Map& map,
1889                                const Converter& converter = Converter()) {
1890       checkConcept<concepts::ReadMap<BlueNode, typename Map::Value>, Map>();
1891       _writer_bits::MapStorageBase<BlueNode>* storage =
1892         new _writer_bits::MapStorage<BlueNode, Map, Converter>(map, converter);
1893       _blue_node_maps.push_back(std::make_pair(caption, storage));
1894       return *this;
1895     }
1896 
1897     /// \brief Edge map writing rule
1898     ///
1899     /// Add an edge map writing rule to the writer.
1900     template <typename Map>
edgeMap(const std::string & caption,const Map & map)1901     BpGraphWriter& edgeMap(const std::string& caption, const Map& map) {
1902       checkConcept<concepts::ReadMap<Edge, typename Map::Value>, Map>();
1903       _writer_bits::MapStorageBase<Edge>* storage =
1904         new _writer_bits::MapStorage<Edge, Map>(map);
1905       _edge_maps.push_back(std::make_pair(caption, storage));
1906       return *this;
1907     }
1908 
1909     /// \brief Edge map writing rule
1910     ///
1911     /// Add an edge map writing rule with specialized converter to the
1912     /// writer.
1913     template <typename Map, typename Converter>
1914     BpGraphWriter& edgeMap(const std::string& caption, const Map& map,
1915                           const Converter& converter = Converter()) {
1916       checkConcept<concepts::ReadMap<Edge, typename Map::Value>, Map>();
1917       _writer_bits::MapStorageBase<Edge>* storage =
1918         new _writer_bits::MapStorage<Edge, Map, Converter>(map, converter);
1919       _edge_maps.push_back(std::make_pair(caption, storage));
1920       return *this;
1921     }
1922 
1923     /// \brief Arc map writing rule
1924     ///
1925     /// Add an arc map writing rule to the writer.
1926     template <typename Map>
arcMap(const std::string & caption,const Map & map)1927     BpGraphWriter& arcMap(const std::string& caption, const Map& map) {
1928       checkConcept<concepts::ReadMap<Arc, typename Map::Value>, Map>();
1929       _writer_bits::MapStorageBase<Edge>* forward_storage =
1930         new _writer_bits::GraphArcMapStorage<BGR, true, Map>(_graph, map);
1931       _edge_maps.push_back(std::make_pair('+' + caption, forward_storage));
1932       _writer_bits::MapStorageBase<Edge>* backward_storage =
1933         new _writer_bits::GraphArcMapStorage<BGR, false, Map>(_graph, map);
1934       _edge_maps.push_back(std::make_pair('-' + caption, backward_storage));
1935       return *this;
1936     }
1937 
1938     /// \brief Arc map writing rule
1939     ///
1940     /// Add an arc map writing rule with specialized converter to the
1941     /// writer.
1942     template <typename Map, typename Converter>
1943     BpGraphWriter& arcMap(const std::string& caption, const Map& map,
1944                           const Converter& converter = Converter()) {
1945       checkConcept<concepts::ReadMap<Arc, typename Map::Value>, Map>();
1946       _writer_bits::MapStorageBase<Edge>* forward_storage =
1947         new _writer_bits::GraphArcMapStorage<BGR, true, Map, Converter>
1948         (_graph, map, converter);
1949       _edge_maps.push_back(std::make_pair('+' + caption, forward_storage));
1950       _writer_bits::MapStorageBase<Edge>* backward_storage =
1951         new _writer_bits::GraphArcMapStorage<BGR, false, Map, Converter>
1952         (_graph, map, converter);
1953       _edge_maps.push_back(std::make_pair('-' + caption, backward_storage));
1954       return *this;
1955     }
1956 
1957     /// \brief Attribute writing rule
1958     ///
1959     /// Add an attribute writing rule to the writer.
1960     template <typename Value>
attribute(const std::string & caption,const Value & value)1961     BpGraphWriter& attribute(const std::string& caption, const Value& value) {
1962       _writer_bits::ValueStorageBase* storage =
1963         new _writer_bits::ValueStorage<Value>(value);
1964       _attributes.push_back(std::make_pair(caption, storage));
1965       return *this;
1966     }
1967 
1968     /// \brief Attribute writing rule
1969     ///
1970     /// Add an attribute writing rule with specialized converter to the
1971     /// writer.
1972     template <typename Value, typename Converter>
1973     BpGraphWriter& attribute(const std::string& caption, const Value& value,
1974                              const Converter& converter = Converter()) {
1975       _writer_bits::ValueStorageBase* storage =
1976         new _writer_bits::ValueStorage<Value, Converter>(value, converter);
1977       _attributes.push_back(std::make_pair(caption, storage));
1978       return *this;
1979     }
1980 
1981     /// \brief Node writing rule
1982     ///
1983     /// Add a node writing rule to the writer.
node(const std::string & caption,const Node & node)1984     BpGraphWriter& node(const std::string& caption, const Node& node) {
1985       typedef _writer_bits::DoubleMapLookUpConverter<
1986         Node, RedNodeIndex, BlueNodeIndex> Converter;
1987       Converter converter(_red_node_index, _blue_node_index);
1988       _writer_bits::ValueStorageBase* storage =
1989         new _writer_bits::ValueStorage<Node, Converter>(node, converter);
1990       _attributes.push_back(std::make_pair(caption, storage));
1991       return *this;
1992     }
1993 
1994     /// \brief Red node writing rule
1995     ///
1996     /// Add a red node writing rule to the writer.
redNode(const std::string & caption,const RedNode & node)1997     BpGraphWriter& redNode(const std::string& caption, const RedNode& node) {
1998       typedef _writer_bits::MapLookUpConverter<Node> Converter;
1999       Converter converter(_red_node_index);
2000       _writer_bits::ValueStorageBase* storage =
2001         new _writer_bits::ValueStorage<Node, Converter>(node, converter);
2002       _attributes.push_back(std::make_pair(caption, storage));
2003       return *this;
2004     }
2005 
2006     /// \brief Blue node writing rule
2007     ///
2008     /// Add a blue node writing rule to the writer.
blueNode(const std::string & caption,const BlueNode & node)2009     BpGraphWriter& blueNode(const std::string& caption, const BlueNode& node) {
2010       typedef _writer_bits::MapLookUpConverter<Node> Converter;
2011       Converter converter(_blue_node_index);
2012       _writer_bits::ValueStorageBase* storage =
2013         new _writer_bits::ValueStorage<Node, Converter>(node, converter);
2014       _attributes.push_back(std::make_pair(caption, storage));
2015       return *this;
2016     }
2017 
2018     /// \brief Edge writing rule
2019     ///
2020     /// Add an edge writing rule to writer.
edge(const std::string & caption,const Edge & edge)2021     BpGraphWriter& edge(const std::string& caption, const Edge& edge) {
2022       typedef _writer_bits::MapLookUpConverter<Edge> Converter;
2023       Converter converter(_edge_index);
2024       _writer_bits::ValueStorageBase* storage =
2025         new _writer_bits::ValueStorage<Edge, Converter>(edge, converter);
2026       _attributes.push_back(std::make_pair(caption, storage));
2027       return *this;
2028     }
2029 
2030     /// \brief Arc writing rule
2031     ///
2032     /// Add an arc writing rule to writer.
arc(const std::string & caption,const Arc & arc)2033     BpGraphWriter& arc(const std::string& caption, const Arc& arc) {
2034       typedef _writer_bits::GraphArcLookUpConverter<BGR> Converter;
2035       Converter converter(_graph, _edge_index);
2036       _writer_bits::ValueStorageBase* storage =
2037         new _writer_bits::ValueStorage<Arc, Converter>(arc, converter);
2038       _attributes.push_back(std::make_pair(caption, storage));
2039       return *this;
2040     }
2041 
2042     /// \name Section Captions
2043     /// @{
2044 
2045     /// \brief Add an additional caption to the \c \@red_nodes and
2046     /// \c \@blue_nodes section
2047     ///
2048     /// Add an additional caption to the \c \@red_nodes and \c
2049     /// \@blue_nodes section.
nodes(const std::string & caption)2050     BpGraphWriter& nodes(const std::string& caption) {
2051       _nodes_caption = caption;
2052       return *this;
2053     }
2054 
2055     /// \brief Add an additional caption to the \c \@edges section
2056     ///
2057     /// Add an additional caption to the \c \@edges section.
edges(const std::string & caption)2058     BpGraphWriter& edges(const std::string& caption) {
2059       _edges_caption = caption;
2060       return *this;
2061     }
2062 
2063     /// \brief Add an additional caption to the \c \@attributes section
2064     ///
2065     /// Add an additional caption to the \c \@attributes section.
attributes(const std::string & caption)2066     BpGraphWriter& attributes(const std::string& caption) {
2067       _attributes_caption = caption;
2068       return *this;
2069     }
2070 
2071     /// \name Skipping Section
2072     /// @{
2073 
2074     /// \brief Skip writing the node set
2075     ///
2076     /// The \c \@red_nodes and \c \@blue_nodes section will not be
2077     /// written to the stream.
skipNodes()2078     BpGraphWriter& skipNodes() {
2079       LEMON_ASSERT(!_skip_nodes, "Multiple usage of skipNodes() member");
2080       _skip_nodes = true;
2081       return *this;
2082     }
2083 
2084     /// \brief Skip writing edge set
2085     ///
2086     /// The \c \@edges section will not be written to the stream.
skipEdges()2087     BpGraphWriter& skipEdges() {
2088       LEMON_ASSERT(!_skip_edges, "Multiple usage of skipEdges() member");
2089       _skip_edges = true;
2090       return *this;
2091     }
2092 
2093     /// @}
2094 
2095   private:
2096 
writeRedNodes()2097     void writeRedNodes() {
2098       _writer_bits::MapStorageBase<RedNode>* label = 0;
2099       for (typename RedNodeMaps::iterator it = _red_node_maps.begin();
2100            it != _red_node_maps.end(); ++it) {
2101         if (it->first == "label") {
2102           label = it->second;
2103           break;
2104         }
2105       }
2106 
2107       *_os << "@red_nodes";
2108       if (!_nodes_caption.empty()) {
2109         _writer_bits::writeToken(*_os << ' ', _nodes_caption);
2110       }
2111       *_os << std::endl;
2112 
2113       if (label == 0) {
2114         *_os << "label" << '\t';
2115       }
2116       for (typename RedNodeMaps::iterator it = _red_node_maps.begin();
2117            it != _red_node_maps.end(); ++it) {
2118         _writer_bits::writeToken(*_os, it->first) << '\t';
2119       }
2120       *_os << std::endl;
2121 
2122       std::vector<RedNode> nodes;
2123       for (RedNodeIt n(_graph); n != INVALID; ++n) {
2124         nodes.push_back(n);
2125       }
2126 
2127       if (label == 0) {
2128         IdMap<BGR, Node> id_map(_graph);
2129         _writer_bits::MapLess<IdMap<BGR, Node> > id_less(id_map);
2130         std::sort(nodes.begin(), nodes.end(), id_less);
2131       } else {
2132         label->sort(nodes);
2133       }
2134 
2135       for (int i = 0; i < static_cast<int>(nodes.size()); ++i) {
2136         RedNode n = nodes[i];
2137         if (label == 0) {
2138           std::ostringstream os;
2139           os << _graph.id(static_cast<Node>(n));
2140           _writer_bits::writeToken(*_os, os.str());
2141           *_os << '\t';
2142           _red_node_index.insert(std::make_pair(n, os.str()));
2143         }
2144         for (typename RedNodeMaps::iterator it = _red_node_maps.begin();
2145              it != _red_node_maps.end(); ++it) {
2146           std::string value = it->second->get(n);
2147           _writer_bits::writeToken(*_os, value);
2148           if (it->first == "label") {
2149             _red_node_index.insert(std::make_pair(n, value));
2150           }
2151           *_os << '\t';
2152         }
2153         *_os << std::endl;
2154       }
2155     }
2156 
writeBlueNodes()2157     void writeBlueNodes() {
2158       _writer_bits::MapStorageBase<BlueNode>* label = 0;
2159       for (typename BlueNodeMaps::iterator it = _blue_node_maps.begin();
2160            it != _blue_node_maps.end(); ++it) {
2161         if (it->first == "label") {
2162           label = it->second;
2163           break;
2164         }
2165       }
2166 
2167       *_os << "@blue_nodes";
2168       if (!_nodes_caption.empty()) {
2169         _writer_bits::writeToken(*_os << ' ', _nodes_caption);
2170       }
2171       *_os << std::endl;
2172 
2173       if (label == 0) {
2174         *_os << "label" << '\t';
2175       }
2176       for (typename BlueNodeMaps::iterator it = _blue_node_maps.begin();
2177            it != _blue_node_maps.end(); ++it) {
2178         _writer_bits::writeToken(*_os, it->first) << '\t';
2179       }
2180       *_os << std::endl;
2181 
2182       std::vector<BlueNode> nodes;
2183       for (BlueNodeIt n(_graph); n != INVALID; ++n) {
2184         nodes.push_back(n);
2185       }
2186 
2187       if (label == 0) {
2188         IdMap<BGR, Node> id_map(_graph);
2189         _writer_bits::MapLess<IdMap<BGR, Node> > id_less(id_map);
2190         std::sort(nodes.begin(), nodes.end(), id_less);
2191       } else {
2192         label->sort(nodes);
2193       }
2194 
2195       for (int i = 0; i < static_cast<int>(nodes.size()); ++i) {
2196         BlueNode n = nodes[i];
2197         if (label == 0) {
2198           std::ostringstream os;
2199           os << _graph.id(static_cast<Node>(n));
2200           _writer_bits::writeToken(*_os, os.str());
2201           *_os << '\t';
2202           _blue_node_index.insert(std::make_pair(n, os.str()));
2203         }
2204         for (typename BlueNodeMaps::iterator it = _blue_node_maps.begin();
2205              it != _blue_node_maps.end(); ++it) {
2206           std::string value = it->second->get(n);
2207           _writer_bits::writeToken(*_os, value);
2208           if (it->first == "label") {
2209             _blue_node_index.insert(std::make_pair(n, value));
2210           }
2211           *_os << '\t';
2212         }
2213         *_os << std::endl;
2214       }
2215     }
2216 
createRedNodeIndex()2217     void createRedNodeIndex() {
2218       _writer_bits::MapStorageBase<RedNode>* label = 0;
2219       for (typename RedNodeMaps::iterator it = _red_node_maps.begin();
2220            it != _red_node_maps.end(); ++it) {
2221         if (it->first == "label") {
2222           label = it->second;
2223           break;
2224         }
2225       }
2226 
2227       if (label == 0) {
2228         for (RedNodeIt n(_graph); n != INVALID; ++n) {
2229           std::ostringstream os;
2230           os << _graph.id(n);
2231           _red_node_index.insert(std::make_pair(n, os.str()));
2232         }
2233       } else {
2234         for (RedNodeIt n(_graph); n != INVALID; ++n) {
2235           std::string value = label->get(n);
2236           _red_node_index.insert(std::make_pair(n, value));
2237         }
2238       }
2239     }
2240 
createBlueNodeIndex()2241     void createBlueNodeIndex() {
2242       _writer_bits::MapStorageBase<BlueNode>* label = 0;
2243       for (typename BlueNodeMaps::iterator it = _blue_node_maps.begin();
2244            it != _blue_node_maps.end(); ++it) {
2245         if (it->first == "label") {
2246           label = it->second;
2247           break;
2248         }
2249       }
2250 
2251       if (label == 0) {
2252         for (BlueNodeIt n(_graph); n != INVALID; ++n) {
2253           std::ostringstream os;
2254           os << _graph.id(n);
2255           _blue_node_index.insert(std::make_pair(n, os.str()));
2256         }
2257       } else {
2258         for (BlueNodeIt n(_graph); n != INVALID; ++n) {
2259           std::string value = label->get(n);
2260           _blue_node_index.insert(std::make_pair(n, value));
2261         }
2262       }
2263     }
2264 
writeEdges()2265     void writeEdges() {
2266       _writer_bits::MapStorageBase<Edge>* label = 0;
2267       for (typename EdgeMaps::iterator it = _edge_maps.begin();
2268            it != _edge_maps.end(); ++it) {
2269         if (it->first == "label") {
2270           label = it->second;
2271           break;
2272         }
2273       }
2274 
2275       *_os << "@edges";
2276       if (!_edges_caption.empty()) {
2277         _writer_bits::writeToken(*_os << ' ', _edges_caption);
2278       }
2279       *_os << std::endl;
2280 
2281       *_os << '\t' << '\t';
2282       if (label == 0) {
2283         *_os << "label" << '\t';
2284       }
2285       for (typename EdgeMaps::iterator it = _edge_maps.begin();
2286            it != _edge_maps.end(); ++it) {
2287         _writer_bits::writeToken(*_os, it->first) << '\t';
2288       }
2289       *_os << std::endl;
2290 
2291       std::vector<Edge> edges;
2292       for (EdgeIt n(_graph); n != INVALID; ++n) {
2293         edges.push_back(n);
2294       }
2295 
2296       if (label == 0) {
2297         IdMap<BGR, Edge> id_map(_graph);
2298         _writer_bits::MapLess<IdMap<BGR, Edge> > id_less(id_map);
2299         std::sort(edges.begin(), edges.end(), id_less);
2300       } else {
2301         label->sort(edges);
2302       }
2303 
2304       for (int i = 0; i < static_cast<int>(edges.size()); ++i) {
2305         Edge e = edges[i];
2306         _writer_bits::writeToken(*_os, _red_node_index.
2307                                  find(_graph.redNode(e))->second);
2308         *_os << '\t';
2309         _writer_bits::writeToken(*_os, _blue_node_index.
2310                                  find(_graph.blueNode(e))->second);
2311         *_os << '\t';
2312         if (label == 0) {
2313           std::ostringstream os;
2314           os << _graph.id(e);
2315           _writer_bits::writeToken(*_os, os.str());
2316           *_os << '\t';
2317           _edge_index.insert(std::make_pair(e, os.str()));
2318         }
2319         for (typename EdgeMaps::iterator it = _edge_maps.begin();
2320              it != _edge_maps.end(); ++it) {
2321           std::string value = it->second->get(e);
2322           _writer_bits::writeToken(*_os, value);
2323           if (it->first == "label") {
2324             _edge_index.insert(std::make_pair(e, value));
2325           }
2326           *_os << '\t';
2327         }
2328         *_os << std::endl;
2329       }
2330     }
2331 
createEdgeIndex()2332     void createEdgeIndex() {
2333       _writer_bits::MapStorageBase<Edge>* label = 0;
2334       for (typename EdgeMaps::iterator it = _edge_maps.begin();
2335            it != _edge_maps.end(); ++it) {
2336         if (it->first == "label") {
2337           label = it->second;
2338           break;
2339         }
2340       }
2341 
2342       if (label == 0) {
2343         for (EdgeIt e(_graph); e != INVALID; ++e) {
2344           std::ostringstream os;
2345           os << _graph.id(e);
2346           _edge_index.insert(std::make_pair(e, os.str()));
2347         }
2348       } else {
2349         for (EdgeIt e(_graph); e != INVALID; ++e) {
2350           std::string value = label->get(e);
2351           _edge_index.insert(std::make_pair(e, value));
2352         }
2353       }
2354     }
2355 
writeAttributes()2356     void writeAttributes() {
2357       if (_attributes.empty()) return;
2358       *_os << "@attributes";
2359       if (!_attributes_caption.empty()) {
2360         _writer_bits::writeToken(*_os << ' ', _attributes_caption);
2361       }
2362       *_os << std::endl;
2363       for (typename Attributes::iterator it = _attributes.begin();
2364            it != _attributes.end(); ++it) {
2365         _writer_bits::writeToken(*_os, it->first) << ' ';
2366         _writer_bits::writeToken(*_os, it->second->get());
2367         *_os << std::endl;
2368       }
2369     }
2370 
2371   public:
2372 
2373     /// \name Execution of the Writer
2374     /// @{
2375 
2376     /// \brief Start the batch processing
2377     ///
2378     /// This function starts the batch processing.
run()2379     void run() {
2380       if (!_skip_nodes) {
2381         writeRedNodes();
2382         writeBlueNodes();
2383       } else {
2384         createRedNodeIndex();
2385         createBlueNodeIndex();
2386       }
2387       if (!_skip_edges) {
2388         writeEdges();
2389       } else {
2390         createEdgeIndex();
2391       }
2392       writeAttributes();
2393     }
2394 
2395     /// \brief Give back the stream of the writer
2396     ///
2397     /// Give back the stream of the writer
ostream()2398     std::ostream& ostream() {
2399       return *_os;
2400     }
2401 
2402     /// @}
2403   };
2404 
2405   /// \ingroup lemon_io
2406   ///
2407   /// \brief Return a \ref lemon::BpGraphWriter "BpGraphWriter" class
2408   ///
2409   /// This function just returns a \ref lemon::BpGraphWriter
2410   /// "BpGraphWriter" class.
2411   ///
2412   /// With this function a bipartite graph can be write to a file or output
2413   /// stream in \ref lgf-format "LGF" format with several maps and
2414   /// attributes. For example, with the following code a bipartite
2415   /// weighted matching problem can be written to the standard output,
2416   /// i.e. a graph with a \e weight map on the edges:
2417   ///
2418   ///\code
2419   ///ListBpGraph graph;
2420   ///ListBpGraph::EdgeMap<int> weight(graph);
2421   ///  // Setting the weight map
2422   ///bpGraphWriter(graph, std::cout).
2423   ///  edgeMap("weight", weight).
2424   ///  run();
2425   ///\endcode
2426   ///
2427   /// For a complete documentation, please see the
2428   /// \ref lemon::BpGraphWriter "BpGraphWriter"
2429   /// class documentation.
2430   /// \warning Don't forget to put the \ref lemon::BpGraphWriter::run() "run()"
2431   /// to the end of the parameter list.
2432   /// \relates BpGraphWriter
2433   /// \sa bpGraphWriter(const TBGR& graph, const std::string& fn)
2434   /// \sa bpGraphWriter(const TBGR& graph, const char* fn)
2435   template <typename TBGR>
bpGraphWriter(const TBGR & graph,std::ostream & os)2436   BpGraphWriter<TBGR> bpGraphWriter(const TBGR& graph, std::ostream& os) {
2437     BpGraphWriter<TBGR> tmp(graph, os);
2438     return tmp;
2439   }
2440 
2441   /// \brief Return a \ref BpGraphWriter class
2442   ///
2443   /// This function just returns a \ref BpGraphWriter class.
2444   /// \relates BpGraphWriter
2445   /// \sa graphWriter(const TBGR& graph, std::ostream& os)
2446   template <typename TBGR>
bpGraphWriter(const TBGR & graph,const std::string & fn)2447   BpGraphWriter<TBGR> bpGraphWriter(const TBGR& graph, const std::string& fn) {
2448     BpGraphWriter<TBGR> tmp(graph, fn);
2449     return tmp;
2450   }
2451 
2452   /// \brief Return a \ref BpGraphWriter class
2453   ///
2454   /// This function just returns a \ref BpGraphWriter class.
2455   /// \relates BpGraphWriter
2456   /// \sa graphWriter(const TBGR& graph, std::ostream& os)
2457   template <typename TBGR>
bpGraphWriter(const TBGR & graph,const char * fn)2458   BpGraphWriter<TBGR> bpGraphWriter(const TBGR& graph, const char* fn) {
2459     BpGraphWriter<TBGR> tmp(graph, fn);
2460     return tmp;
2461   }
2462 
2463   class SectionWriter;
2464 
2465   SectionWriter sectionWriter(std::istream& is);
2466   SectionWriter sectionWriter(const std::string& fn);
2467   SectionWriter sectionWriter(const char* fn);
2468 
2469   /// \ingroup lemon_io
2470   ///
2471   /// \brief Section writer class
2472   ///
2473   /// In the \ref lgf-format "LGF" file extra sections can be placed,
2474   /// which contain any data in arbitrary format. Such sections can be
2475   /// written with this class. A writing rule can be added to the
2476   /// class with two different functions. With the \c sectionLines()
2477   /// function a generator can write the section line-by-line, while
2478   /// with the \c sectionStream() member the section can be written to
2479   /// an output stream.
2480   class SectionWriter {
2481   private:
2482 
2483     std::ostream* _os;
2484     bool local_os;
2485 
2486     typedef std::vector<std::pair<std::string, _writer_bits::Section*> >
2487     Sections;
2488 
2489     Sections _sections;
2490 
2491   public:
2492 
2493     /// \brief Constructor
2494     ///
2495     /// Construct a section writer, which writes to the given output
2496     /// stream.
SectionWriter(std::ostream & os)2497     SectionWriter(std::ostream& os)
2498       : _os(&os), local_os(false) {}
2499 
2500     /// \brief Constructor
2501     ///
2502     /// Construct a section writer, which writes into the given file.
SectionWriter(const std::string & fn)2503     SectionWriter(const std::string& fn)
2504       : _os(new std::ofstream(fn.c_str())), local_os(true) {
2505       if (!(*_os)) {
2506         delete _os;
2507         throw IoError("Cannot write file", fn);
2508       }
2509     }
2510 
2511     /// \brief Constructor
2512     ///
2513     /// Construct a section writer, which writes into the given file.
SectionWriter(const char * fn)2514     SectionWriter(const char* fn)
2515       : _os(new std::ofstream(fn)), local_os(true) {
2516       if (!(*_os)) {
2517         delete _os;
2518         throw IoError("Cannot write file", fn);
2519       }
2520     }
2521 
2522     /// \brief Destructor
~SectionWriter()2523     ~SectionWriter() {
2524       for (Sections::iterator it = _sections.begin();
2525            it != _sections.end(); ++it) {
2526         delete it->second;
2527       }
2528 
2529       if (local_os) {
2530         delete _os;
2531       }
2532 
2533     }
2534 
2535   private:
2536 
2537     friend SectionWriter sectionWriter(std::ostream& os);
2538     friend SectionWriter sectionWriter(const std::string& fn);
2539     friend SectionWriter sectionWriter(const char* fn);
2540 
SectionWriter(SectionWriter & other)2541     SectionWriter(SectionWriter& other)
2542       : _os(other._os), local_os(other.local_os) {
2543 
2544       other._os = 0;
2545       other.local_os = false;
2546 
2547       _sections.swap(other._sections);
2548     }
2549 
2550     SectionWriter& operator=(const SectionWriter&);
2551 
2552   public:
2553 
2554     /// \name Section Writers
2555     /// @{
2556 
2557     /// \brief Add a section writer with line oriented writing
2558     ///
2559     /// The first parameter is the type descriptor of the section, the
2560     /// second is a generator with std::string values. At the writing
2561     /// process, the returned \c std::string will be written into the
2562     /// output file until it is an empty string.
2563     ///
2564     /// For example, an integer vector is written into a section.
2565     ///\code
2566     ///  @numbers
2567     ///  12 45 23 78
2568     ///  4 28 38 28
2569     ///  23 6 16
2570     ///\endcode
2571     ///
2572     /// The generator is implemented as a struct.
2573     ///\code
2574     ///  struct NumberSection {
2575     ///    std::vector<int>::const_iterator _it, _end;
2576     ///    NumberSection(const std::vector<int>& data)
2577     ///      : _it(data.begin()), _end(data.end()) {}
2578     ///    std::string operator()() {
2579     ///      int rem_in_line = 4;
2580     ///      std::ostringstream ls;
2581     ///      while (rem_in_line > 0 && _it != _end) {
2582     ///        ls << *(_it++) << ' ';
2583     ///        --rem_in_line;
2584     ///      }
2585     ///      return ls.str();
2586     ///    }
2587     ///  };
2588     ///
2589     ///  // ...
2590     ///
2591     ///  writer.sectionLines("numbers", NumberSection(vec));
2592     ///\endcode
2593     template <typename Functor>
sectionLines(const std::string & type,Functor functor)2594     SectionWriter& sectionLines(const std::string& type, Functor functor) {
2595       LEMON_ASSERT(!type.empty(), "Type is empty.");
2596       _sections.push_back(std::make_pair(type,
2597         new _writer_bits::LineSection<Functor>(functor)));
2598       return *this;
2599     }
2600 
2601 
2602     /// \brief Add a section writer with stream oriented writing
2603     ///
2604     /// The first parameter is the type of the section, the second is
2605     /// a functor, which takes a \c std::ostream& parameter. The
2606     /// functor writes the section to the output stream.
2607     /// \warning The last line must be closed with end-line character.
2608     template <typename Functor>
sectionStream(const std::string & type,Functor functor)2609     SectionWriter& sectionStream(const std::string& type, Functor functor) {
2610       LEMON_ASSERT(!type.empty(), "Type is empty.");
2611       _sections.push_back(std::make_pair(type,
2612          new _writer_bits::StreamSection<Functor>(functor)));
2613       return *this;
2614     }
2615 
2616     /// @}
2617 
2618   public:
2619 
2620 
2621     /// \name Execution of the Writer
2622     /// @{
2623 
2624     /// \brief Start the batch processing
2625     ///
2626     /// This function starts the batch processing.
run()2627     void run() {
2628 
2629       LEMON_ASSERT(_os != 0, "This writer is assigned to an other writer");
2630 
2631       for (Sections::iterator it = _sections.begin();
2632            it != _sections.end(); ++it) {
2633         (*_os) << '@' << it->first << std::endl;
2634         it->second->process(*_os);
2635       }
2636     }
2637 
2638     /// \brief Give back the stream of the writer
2639     ///
2640     /// Returns the stream of the writer
ostream()2641     std::ostream& ostream() {
2642       return *_os;
2643     }
2644 
2645     /// @}
2646 
2647   };
2648 
2649   /// \ingroup lemon_io
2650   ///
2651   /// \brief Return a \ref SectionWriter class
2652   ///
2653   /// This function just returns a \ref SectionWriter class.
2654   ///
2655   /// Please see SectionWriter documentation about the custom section
2656   /// output.
2657   ///
2658   /// \relates SectionWriter
2659   /// \sa sectionWriter(const std::string& fn)
2660   /// \sa sectionWriter(const char *fn)
sectionWriter(std::ostream & os)2661   inline SectionWriter sectionWriter(std::ostream& os) {
2662     SectionWriter tmp(os);
2663     return tmp;
2664   }
2665 
2666   /// \brief Return a \ref SectionWriter class
2667   ///
2668   /// This function just returns a \ref SectionWriter class.
2669   /// \relates SectionWriter
2670   /// \sa sectionWriter(std::ostream& os)
sectionWriter(const std::string & fn)2671   inline SectionWriter sectionWriter(const std::string& fn) {
2672     SectionWriter tmp(fn);
2673     return tmp;
2674   }
2675 
2676   /// \brief Return a \ref SectionWriter class
2677   ///
2678   /// This function just returns a \ref SectionWriter class.
2679   /// \relates SectionWriter
2680   /// \sa sectionWriter(std::ostream& os)
sectionWriter(const char * fn)2681   inline SectionWriter sectionWriter(const char* fn) {
2682     SectionWriter tmp(fn);
2683     return tmp;
2684   }
2685 }
2686 
2687 #endif
2688