1 /* -*- mode: C++; indent-tabs-mode: nil; -*-
3 * This file is a part of LEMON, a generic C++ optimization library.
5 * Copyright (C) 2003-2013
6 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
7 * (Egervary Research Group on Combinatorial Optimization, EGRES).
9 * Permission to use, modify and distribute this software is granted
10 * provided that this copyright notice appears in all copies. For
11 * precise terms see the accompanying LICENSE file.
13 * This software is provided "AS IS" with no warranty of any kind,
14 * express or implied, and with no claim as to its suitability for any
21 ///\brief \ref lgf-format "LEMON Graph Format" writer.
24 #ifndef LEMON_LGF_WRITER_H
25 #define LEMON_LGF_WRITER_H
36 #include <lemon/core.h>
37 #include <lemon/maps.h>
39 #include <lemon/concept_check.h>
40 #include <lemon/concepts/maps.h>
44 namespace _writer_bits {
46 template <typename Value>
47 struct DefaultConverter {
48 std::string operator()(const Value& value) {
49 std::ostringstream os;
56 bool operator<(const T&, const T&) {
57 throw FormatError("Label map is not comparable");
60 template <typename _Map>
64 typedef typename Map::Key Item;
70 MapLess(const Map& map) : _map(map) {}
72 bool operator()(const Item& left, const Item& right) {
73 return _map[left] < _map[right];
77 template <typename _Graph, bool _dir, typename _Map>
78 class GraphArcMapLess {
82 typedef typename Graph::Edge Item;
89 GraphArcMapLess(const Graph& graph, const Map& map)
90 : _graph(graph), _map(map) {}
92 bool operator()(const Item& left, const Item& right) {
93 return _map[_graph.direct(left, _dir)] <
94 _map[_graph.direct(right, _dir)];
98 template <typename _Item>
99 class MapStorageBase {
105 virtual ~MapStorageBase() {}
107 virtual std::string get(const Item& item) = 0;
108 virtual void sort(std::vector<Item>&) = 0;
111 template <typename _Item, typename _Map,
112 typename _Converter = DefaultConverter<typename _Map::Value> >
113 class MapStorage : public MapStorageBase<_Item> {
116 typedef _Converter Converter;
121 Converter _converter;
124 MapStorage(const Map& map, const Converter& converter = Converter())
125 : _map(map), _converter(converter) {}
126 virtual ~MapStorage() {}
128 virtual std::string get(const Item& item) {
129 return _converter(_map[item]);
131 virtual void sort(std::vector<Item>& items) {
132 MapLess<Map> less(_map);
133 std::sort(items.begin(), items.end(), less);
137 template <typename _Graph, bool _dir, typename _Map,
138 typename _Converter = DefaultConverter<typename _Map::Value> >
139 class GraphArcMapStorage : public MapStorageBase<typename _Graph::Edge> {
142 typedef _Converter Converter;
143 typedef _Graph Graph;
144 typedef typename Graph::Edge Item;
145 static const bool dir = _dir;
150 Converter _converter;
153 GraphArcMapStorage(const Graph& graph, const Map& map,
154 const Converter& converter = Converter())
155 : _graph(graph), _map(map), _converter(converter) {}
156 virtual ~GraphArcMapStorage() {}
158 virtual std::string get(const Item& item) {
159 return _converter(_map[_graph.direct(item, dir)]);
161 virtual void sort(std::vector<Item>& items) {
162 GraphArcMapLess<Graph, dir, Map> less(_graph, _map);
163 std::sort(items.begin(), items.end(), less);
167 class ValueStorageBase {
169 ValueStorageBase() {}
170 virtual ~ValueStorageBase() {}
172 virtual std::string get() = 0;
175 template <typename _Value, typename _Converter = DefaultConverter<_Value> >
176 class ValueStorage : public ValueStorageBase {
178 typedef _Value Value;
179 typedef _Converter Converter;
183 Converter _converter;
186 ValueStorage(const Value& value, const Converter& converter = Converter())
187 : _value(value), _converter(converter) {}
189 virtual std::string get() {
190 return _converter(_value);
194 template <typename Value,
195 typename Map = std::map<Value, std::string> >
196 struct MapLookUpConverter {
199 MapLookUpConverter(const Map& map)
202 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");
211 template <typename Value,
212 typename Map1 = std::map<Value, std::string>,
213 typename Map2 = std::map<Value, std::string> >
214 struct DoubleMapLookUpConverter {
218 DoubleMapLookUpConverter(const Map1& map1, const Map2& map2)
219 : _map1(map1), _map2(map2) {}
221 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");
231 if (it2 == _map2.end()) {
234 throw FormatError("Item is ambigous");
240 template <typename Graph>
241 struct GraphArcLookUpConverter {
243 const std::map<typename Graph::Edge, std::string>& _map;
245 GraphArcLookUpConverter(const Graph& graph,
246 const std::map<typename Graph::Edge,
248 : _graph(graph), _map(map) {}
250 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");
256 return (_graph.direction(val) ? '+' : '-') + it->second;
260 inline bool isWhiteSpace(char c) {
261 return c == ' ' || c == '\t' || c == '\v' ||
262 c == '\n' || c == '\r' || c == '\f';
265 inline bool isEscaped(char c) {
266 return c == '\\' || c == '\"' || c == '\'' ||
267 c == '\a' || c == '\b';
270 inline static void writeEscape(std::ostream& os, char c) {
301 std::ios::fmtflags flags = os.flags();
302 os << '\\' << std::oct << static_cast<int>(c);
311 inline bool requireEscape(const std::string& str) {
312 if (str.empty() || str[0] == '@') return true;
313 std::istringstream is(str);
316 if (isWhiteSpace(c) || isEscaped(c)) {
323 inline std::ostream& writeToken(std::ostream& os, const std::string& str) {
325 if (requireEscape(str)) {
327 for (std::string::const_iterator it = str.begin();
328 it != str.end(); ++it) {
329 writeEscape(os, *it);
340 virtual ~Section() {}
341 virtual void process(std::ostream& os) = 0;
344 template <typename Functor>
345 class LineSection : public Section {
352 LineSection(const Functor& functor) : _functor(functor) {}
353 virtual ~LineSection() {}
355 virtual void process(std::ostream& os) {
357 while (!(line = _functor()).empty()) os << line << std::endl;
361 template <typename Functor>
362 class StreamSection : public Section {
369 StreamSection(const Functor& functor) : _functor(functor) {}
370 virtual ~StreamSection() {}
372 virtual void process(std::ostream& os) {
379 template <typename DGR>
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);
388 template <typename TDGR>
389 DigraphWriter<TDGR> digraphWriter(const TDGR& digraph, const char* fn);
392 /// \ingroup lemon_io
394 /// \brief \ref lgf-format "LGF" writer for directed graphs
396 /// This utility writes an \ref lgf-format "LGF" file.
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.
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).
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.
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 {
441 TEMPLATE_DIGRAPH_TYPEDEFS(DGR);
451 std::string _nodes_caption;
452 std::string _arcs_caption;
453 std::string _attributes_caption;
455 typedef std::map<Node, std::string> NodeIndex;
456 NodeIndex _node_index;
457 typedef std::map<Arc, std::string> ArcIndex;
460 typedef std::vector<std::pair<std::string,
461 _writer_bits::MapStorageBase<Node>* > > NodeMaps;
464 typedef std::vector<std::pair<std::string,
465 _writer_bits::MapStorageBase<Arc>* > >ArcMaps;
468 typedef std::vector<std::pair<std::string,
469 _writer_bits::ValueStorageBase*> > Attributes;
470 Attributes _attributes;
477 /// \brief Constructor
479 /// Construct a directed graph writer, which writes to the given
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) {}
485 /// \brief Constructor
487 /// Construct a directed graph writer, which writes to the given
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) {
494 throw IoError("Cannot write file", fn);
498 /// \brief Constructor
500 /// Construct a directed graph writer, which writes to the given
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) {
507 throw IoError("Cannot write file", fn);
511 /// \brief Destructor
513 for (typename NodeMaps::iterator it = _node_maps.begin();
514 it != _node_maps.end(); ++it) {
518 for (typename ArcMaps::iterator it = _arc_maps.begin();
519 it != _arc_maps.end(); ++it) {
523 for (typename Attributes::iterator it = _attributes.begin();
524 it != _attributes.end(); ++it) {
535 template <typename TDGR>
536 friend DigraphWriter<TDGR> digraphWriter(const TDGR& digraph,
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,
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) {
550 other.local_os = false;
552 _node_index.swap(other._node_index);
553 _arc_index.swap(other._arc_index);
555 _node_maps.swap(other._node_maps);
556 _arc_maps.swap(other._arc_maps);
557 _attributes.swap(other._attributes);
559 _nodes_caption = other._nodes_caption;
560 _arcs_caption = other._arcs_caption;
561 _attributes_caption = other._attributes_caption;
564 DigraphWriter& operator=(const DigraphWriter&);
568 /// \name Writing Rules
571 /// \brief Node map writing rule
573 /// Add a node map writing rule to the writer.
574 template <typename 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));
583 /// \brief Node map writing rule
585 /// Add a node map writing rule with specialized converter to the
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));
597 /// \brief Arc map writing rule
599 /// Add an arc map writing rule to the writer.
600 template <typename 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));
609 /// \brief Arc map writing rule
611 /// Add an arc map writing rule with specialized converter to the
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));
623 /// \brief Attribute writing rule
625 /// Add an attribute writing rule to the writer.
626 template <typename 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));
634 /// \brief Attribute writing rule
636 /// Add an attribute writing rule with specialized converter to the
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));
647 /// \brief Node writing rule
649 /// Add a node writing rule to the writer.
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));
659 /// \brief Arc writing rule
661 /// Add an arc writing rule to writer.
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));
671 /// \name Section Captions
674 /// \brief Add an additional caption to the \c \@nodes section
676 /// Add an additional caption to the \c \@nodes section.
677 DigraphWriter& nodes(const std::string& caption) {
678 _nodes_caption = caption;
682 /// \brief Add an additional caption to the \c \@arcs section
684 /// Add an additional caption to the \c \@arcs section.
685 DigraphWriter& arcs(const std::string& caption) {
686 _arcs_caption = caption;
690 /// \brief Add an additional caption to the \c \@attributes section
692 /// Add an additional caption to the \c \@attributes section.
693 DigraphWriter& attributes(const std::string& caption) {
694 _attributes_caption = caption;
698 /// \name Skipping Section
701 /// \brief Skip writing the node set
703 /// The \c \@nodes section will not be written to the stream.
704 DigraphWriter& skipNodes() {
705 LEMON_ASSERT(!_skip_nodes, "Multiple usage of skipNodes() member");
710 /// \brief Skip writing arc set
712 /// The \c \@arcs section will not be written to the stream.
713 DigraphWriter& skipArcs() {
714 LEMON_ASSERT(!_skip_arcs, "Multiple usage of skipArcs() member");
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") {
734 if (!_nodes_caption.empty()) {
735 _writer_bits::writeToken(*_os << ' ', _nodes_caption);
740 *_os << "label" << '\t';
742 for (typename NodeMaps::iterator it = _node_maps.begin();
743 it != _node_maps.end(); ++it) {
744 _writer_bits::writeToken(*_os, it->first) << '\t';
748 std::vector<Node> nodes;
749 for (NodeIt n(_digraph); n != INVALID; ++n) {
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);
761 for (int i = 0; i < static_cast<int>(nodes.size()); ++i) {
764 std::ostringstream os;
765 os << _digraph.id(n);
766 _writer_bits::writeToken(*_os, os.str());
768 _node_index.insert(std::make_pair(n, os.str()));
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));
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") {
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()));
800 for (NodeIt n(_digraph); n != INVALID; ++n) {
801 std::string value = label->get(n);
802 _node_index.insert(std::make_pair(n, value));
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") {
818 if (!_arcs_caption.empty()) {
819 _writer_bits::writeToken(*_os << ' ', _arcs_caption);
823 *_os << '\t' << '\t';
825 *_os << "label" << '\t';
827 for (typename ArcMaps::iterator it = _arc_maps.begin();
828 it != _arc_maps.end(); ++it) {
829 _writer_bits::writeToken(*_os, it->first) << '\t';
833 std::vector<Arc> arcs;
834 for (ArcIt n(_digraph); n != INVALID; ++n) {
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);
846 for (int i = 0; i < static_cast<int>(arcs.size()); ++i) {
848 _writer_bits::writeToken(*_os, _node_index.
849 find(_digraph.source(a))->second);
851 _writer_bits::writeToken(*_os, _node_index.
852 find(_digraph.target(a))->second);
855 std::ostringstream os;
856 os << _digraph.id(a);
857 _writer_bits::writeToken(*_os, os.str());
859 _arc_index.insert(std::make_pair(a, os.str()));
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));
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") {
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()));
891 for (ArcIt a(_digraph); a != INVALID; ++a) {
892 std::string value = label->get(a);
893 _arc_index.insert(std::make_pair(a, value));
898 void writeAttributes() {
899 if (_attributes.empty()) return;
900 *_os << "@attributes";
901 if (!_attributes_caption.empty()) {
902 _writer_bits::writeToken(*_os << ' ', _attributes_caption);
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());
915 /// \name Execution of the Writer
918 /// \brief Start the batch processing
920 /// This function starts the batch processing.
935 /// \brief Give back the stream of the writer
937 /// Give back the stream of the writer.
938 std::ostream& ostream() {
945 /// \ingroup lemon_io
947 /// \brief Return a \ref lemon::DigraphWriter "DigraphWriter" class
949 /// This function just returns a \ref lemon::DigraphWriter
950 /// "DigraphWriter" class.
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
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).
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>
980 DigraphWriter<TDGR> digraphWriter(const TDGR& digraph, std::ostream& os) {
981 DigraphWriter<TDGR> tmp(digraph, os);
985 /// \brief Return a \ref DigraphWriter class
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>
991 DigraphWriter<TDGR> digraphWriter(const TDGR& digraph,
992 const std::string& fn) {
993 DigraphWriter<TDGR> tmp(digraph, fn);
997 /// \brief Return a \ref DigraphWriter class
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>
1003 DigraphWriter<TDGR> digraphWriter(const TDGR& digraph, const char* fn) {
1004 DigraphWriter<TDGR> tmp(digraph, fn);
1008 template <typename GR>
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);
1018 /// \ingroup lemon_io
1020 /// \brief \ref lgf-format "LGF" writer for undirected graphs
1022 /// This utility writes an \ref lgf-format "LGF" file.
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.
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>
1038 TEMPLATE_GRAPH_TYPEDEFS(GR);
1048 std::string _nodes_caption;
1049 std::string _edges_caption;
1050 std::string _attributes_caption;
1052 typedef std::map<Node, std::string> NodeIndex;
1053 NodeIndex _node_index;
1054 typedef std::map<Edge, std::string> EdgeIndex;
1055 EdgeIndex _edge_index;
1057 typedef std::vector<std::pair<std::string,
1058 _writer_bits::MapStorageBase<Node>* > > NodeMaps;
1059 NodeMaps _node_maps;
1061 typedef std::vector<std::pair<std::string,
1062 _writer_bits::MapStorageBase<Edge>* > >EdgeMaps;
1063 EdgeMaps _edge_maps;
1065 typedef std::vector<std::pair<std::string,
1066 _writer_bits::ValueStorageBase*> > Attributes;
1067 Attributes _attributes;
1074 /// \brief Constructor
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) {}
1082 /// \brief Constructor
1084 /// Construct a undirected graph writer, which writes to the given
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) {
1091 throw IoError("Cannot write file", fn);
1095 /// \brief Constructor
1097 /// Construct a undirected graph writer, which writes to the given
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) {
1104 throw IoError("Cannot write file", fn);
1108 /// \brief Destructor
1110 for (typename NodeMaps::iterator it = _node_maps.begin();
1111 it != _node_maps.end(); ++it) {
1115 for (typename EdgeMaps::iterator it = _edge_maps.begin();
1116 it != _edge_maps.end(); ++it) {
1120 for (typename Attributes::iterator it = _attributes.begin();
1121 it != _attributes.end(); ++it) {
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);
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) {
1145 other.local_os = false;
1147 _node_index.swap(other._node_index);
1148 _edge_index.swap(other._edge_index);
1150 _node_maps.swap(other._node_maps);
1151 _edge_maps.swap(other._edge_maps);
1152 _attributes.swap(other._attributes);
1154 _nodes_caption = other._nodes_caption;
1155 _edges_caption = other._edges_caption;
1156 _attributes_caption = other._attributes_caption;
1159 GraphWriter& operator=(const GraphWriter&);
1163 /// \name Writing Rules
1166 /// \brief Node map writing rule
1168 /// Add a node map writing rule to the writer.
1169 template <typename 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));
1178 /// \brief Node map writing rule
1180 /// Add a node map writing rule with specialized converter to the
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));
1192 /// \brief Edge map writing rule
1194 /// Add an edge map writing rule to the writer.
1195 template <typename 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));
1204 /// \brief Edge map writing rule
1206 /// Add an edge map writing rule with specialized converter to the
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));
1218 /// \brief Arc map writing rule
1220 /// Add an arc map writing rule to the writer.
1221 template <typename 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));
1233 /// \brief Arc map writing rule
1235 /// Add an arc map writing rule with specialized converter to the
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));
1252 /// \brief Attribute writing rule
1254 /// Add an attribute writing rule to the writer.
1255 template <typename 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));
1263 /// \brief Attribute writing rule
1265 /// Add an attribute writing rule with specialized converter to the
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));
1276 /// \brief Node writing rule
1278 /// Add a node writing rule to the writer.
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));
1288 /// \brief Edge writing rule
1290 /// Add an edge writing rule to writer.
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));
1300 /// \brief Arc writing rule
1302 /// Add an arc writing rule to writer.
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));
1312 /// \name Section Captions
1315 /// \brief Add an additional caption to the \c \@nodes section
1317 /// Add an additional caption to the \c \@nodes section.
1318 GraphWriter& nodes(const std::string& caption) {
1319 _nodes_caption = caption;
1323 /// \brief Add an additional caption to the \c \@edges section
1325 /// Add an additional caption to the \c \@edges section.
1326 GraphWriter& edges(const std::string& caption) {
1327 _edges_caption = caption;
1331 /// \brief Add an additional caption to the \c \@attributes section
1333 /// Add an additional caption to the \c \@attributes section.
1334 GraphWriter& attributes(const std::string& caption) {
1335 _attributes_caption = caption;
1339 /// \name Skipping Section
1342 /// \brief Skip writing the node set
1344 /// The \c \@nodes section will not be written to the stream.
1345 GraphWriter& skipNodes() {
1346 LEMON_ASSERT(!_skip_nodes, "Multiple usage of skipNodes() member");
1351 /// \brief Skip writing edge set
1353 /// The \c \@edges section will not be written to the stream.
1354 GraphWriter& skipEdges() {
1355 LEMON_ASSERT(!_skip_edges, "Multiple usage of skipEdges() member");
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") {
1375 if (!_nodes_caption.empty()) {
1376 _writer_bits::writeToken(*_os << ' ', _nodes_caption);
1381 *_os << "label" << '\t';
1383 for (typename NodeMaps::iterator it = _node_maps.begin();
1384 it != _node_maps.end(); ++it) {
1385 _writer_bits::writeToken(*_os, it->first) << '\t';
1389 std::vector<Node> nodes;
1390 for (NodeIt n(_graph); n != INVALID; ++n) {
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);
1402 for (int i = 0; i < static_cast<int>(nodes.size()); ++i) {
1405 std::ostringstream os;
1407 _writer_bits::writeToken(*_os, os.str());
1409 _node_index.insert(std::make_pair(n, os.str()));
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));
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") {
1435 for (NodeIt n(_graph); n != INVALID; ++n) {
1436 std::ostringstream os;
1438 _node_index.insert(std::make_pair(n, os.str()));
1441 for (NodeIt n(_graph); n != INVALID; ++n) {
1442 std::string value = label->get(n);
1443 _node_index.insert(std::make_pair(n, value));
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") {
1459 if (!_edges_caption.empty()) {
1460 _writer_bits::writeToken(*_os << ' ', _edges_caption);
1464 *_os << '\t' << '\t';
1466 *_os << "label" << '\t';
1468 for (typename EdgeMaps::iterator it = _edge_maps.begin();
1469 it != _edge_maps.end(); ++it) {
1470 _writer_bits::writeToken(*_os, it->first) << '\t';
1474 std::vector<Edge> edges;
1475 for (EdgeIt n(_graph); n != INVALID; ++n) {
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);
1487 for (int i = 0; i < static_cast<int>(edges.size()); ++i) {
1489 _writer_bits::writeToken(*_os, _node_index.
1490 find(_graph.u(e))->second);
1492 _writer_bits::writeToken(*_os, _node_index.
1493 find(_graph.v(e))->second);
1496 std::ostringstream os;
1498 _writer_bits::writeToken(*_os, os.str());
1500 _edge_index.insert(std::make_pair(e, os.str()));
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));
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") {
1526 for (EdgeIt e(_graph); e != INVALID; ++e) {
1527 std::ostringstream os;
1529 _edge_index.insert(std::make_pair(e, os.str()));
1532 for (EdgeIt e(_graph); e != INVALID; ++e) {
1533 std::string value = label->get(e);
1534 _edge_index.insert(std::make_pair(e, value));
1539 void writeAttributes() {
1540 if (_attributes.empty()) return;
1541 *_os << "@attributes";
1542 if (!_attributes_caption.empty()) {
1543 _writer_bits::writeToken(*_os << ' ', _attributes_caption);
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());
1556 /// \name Execution of the Writer
1559 /// \brief Start the batch processing
1561 /// This function starts the batch processing.
1576 /// \brief Give back the stream of the writer
1578 /// Give back the stream of the writer
1579 std::ostream& ostream() {
1586 /// \ingroup lemon_io
1588 /// \brief Return a \ref lemon::GraphWriter "GraphWriter" class
1590 /// This function just returns a \ref lemon::GraphWriter "GraphWriter" class.
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:
1600 ///ListGraph::EdgeMap<int> weight(graph);
1601 /// // Setting the weight map
1602 ///graphWriter(graph, std::cout).
1603 /// edgeMap("weight", weight).
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>
1616 GraphWriter<TGR> graphWriter(const TGR& graph, std::ostream& os) {
1617 GraphWriter<TGR> tmp(graph, os);
1621 /// \brief Return a \ref GraphWriter class
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>
1627 GraphWriter<TGR> graphWriter(const TGR& graph, const std::string& fn) {
1628 GraphWriter<TGR> tmp(graph, fn);
1632 /// \brief Return a \ref GraphWriter class
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>
1638 GraphWriter<TGR> graphWriter(const TGR& graph, const char* fn) {
1639 GraphWriter<TGR> tmp(graph, fn);
1643 template <typename BGR>
1644 class BpGraphWriter;
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);
1654 /// \ingroup lemon_io
1656 /// \brief \ref lgf-format "LGF" writer for undirected bipartite graphs
1658 /// This utility writes an \ref lgf-format "LGF" file.
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.
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 {
1671 typedef BGR BpGraph;
1672 TEMPLATE_BPGRAPH_TYPEDEFS(BGR);
1682 std::string _nodes_caption;
1683 std::string _edges_caption;
1684 std::string _attributes_caption;
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;
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;
1700 typedef std::vector<std::pair<std::string,
1701 _writer_bits::MapStorageBase<Edge>* > >EdgeMaps;
1702 EdgeMaps _edge_maps;
1704 typedef std::vector<std::pair<std::string,
1705 _writer_bits::ValueStorageBase*> > Attributes;
1706 Attributes _attributes;
1713 /// \brief Constructor
1715 /// Construct a bipartite graph writer, which writes to the given
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) {}
1721 /// \brief Constructor
1723 /// Construct a bipartite graph writer, which writes to the given
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) {
1730 throw IoError("Cannot write file", fn);
1734 /// \brief Constructor
1736 /// Construct a bipartite graph writer, which writes to the given
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) {
1743 throw IoError("Cannot write file", fn);
1747 /// \brief Destructor
1749 for (typename RedNodeMaps::iterator it = _red_node_maps.begin();
1750 it != _red_node_maps.end(); ++it) {
1754 for (typename BlueNodeMaps::iterator it = _blue_node_maps.begin();
1755 it != _blue_node_maps.end(); ++it) {
1759 for (typename EdgeMaps::iterator it = _edge_maps.begin();
1760 it != _edge_maps.end(); ++it) {
1764 for (typename Attributes::iterator it = _attributes.begin();
1765 it != _attributes.end(); ++it) {
1776 template <typename TBGR>
1777 friend BpGraphWriter<TBGR> bpGraphWriter(const TBGR& graph,
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);
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) {
1790 other.local_os = false;
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);
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);
1801 _nodes_caption = other._nodes_caption;
1802 _edges_caption = other._edges_caption;
1803 _attributes_caption = other._attributes_caption;
1806 BpGraphWriter& operator=(const BpGraphWriter&);
1810 /// \name Writing Rules
1813 /// \brief Node map writing rule
1815 /// Add a node map writing rule to the writer.
1816 template <typename 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));
1828 /// \brief Node map writing rule
1830 /// Add a node map writing rule with specialized converter to the
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));
1845 /// \brief Red node map writing rule
1847 /// Add a red node map writing rule to the writer.
1848 template <typename 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));
1857 /// \brief Red node map writing rule
1859 /// Add a red node map writing rule with specialized converter to the
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));
1871 /// \brief Blue node map writing rule
1873 /// Add a blue node map writing rule to the writer.
1874 template <typename 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));
1883 /// \brief Blue node map writing rule
1885 /// Add a blue node map writing rule with specialized converter to the
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));
1897 /// \brief Edge map writing rule
1899 /// Add an edge map writing rule to the writer.
1900 template <typename 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));
1909 /// \brief Edge map writing rule
1911 /// Add an edge map writing rule with specialized converter to the
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));
1923 /// \brief Arc map writing rule
1925 /// Add an arc map writing rule to the writer.
1926 template <typename 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));
1938 /// \brief Arc map writing rule
1940 /// Add an arc map writing rule with specialized converter to the
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));
1957 /// \brief Attribute writing rule
1959 /// Add an attribute writing rule to the writer.
1960 template <typename 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));
1968 /// \brief Attribute writing rule
1970 /// Add an attribute writing rule with specialized converter to the
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));
1981 /// \brief Node writing rule
1983 /// Add a node writing rule to the writer.
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));
1994 /// \brief Red node writing rule
1996 /// Add a red node writing rule to the writer.
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));
2006 /// \brief Blue node writing rule
2008 /// Add a blue node writing rule to the writer.
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));
2018 /// \brief Edge writing rule
2020 /// Add an edge writing rule to writer.
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));
2030 /// \brief Arc writing rule
2032 /// Add an arc writing rule to writer.
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));
2042 /// \name Section Captions
2045 /// \brief Add an additional caption to the \c \@red_nodes and
2046 /// \c \@blue_nodes section
2048 /// Add an additional caption to the \c \@red_nodes and \c
2049 /// \@blue_nodes section.
2050 BpGraphWriter& nodes(const std::string& caption) {
2051 _nodes_caption = caption;
2055 /// \brief Add an additional caption to the \c \@edges section
2057 /// Add an additional caption to the \c \@edges section.
2058 BpGraphWriter& edges(const std::string& caption) {
2059 _edges_caption = caption;
2063 /// \brief Add an additional caption to the \c \@attributes section
2065 /// Add an additional caption to the \c \@attributes section.
2066 BpGraphWriter& attributes(const std::string& caption) {
2067 _attributes_caption = caption;
2071 /// \name Skipping Section
2074 /// \brief Skip writing the node set
2076 /// The \c \@red_nodes and \c \@blue_nodes section will not be
2077 /// written to the stream.
2078 BpGraphWriter& skipNodes() {
2079 LEMON_ASSERT(!_skip_nodes, "Multiple usage of skipNodes() member");
2084 /// \brief Skip writing edge set
2086 /// The \c \@edges section will not be written to the stream.
2087 BpGraphWriter& skipEdges() {
2088 LEMON_ASSERT(!_skip_edges, "Multiple usage of skipEdges() member");
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") {
2107 *_os << "@red_nodes";
2108 if (!_nodes_caption.empty()) {
2109 _writer_bits::writeToken(*_os << ' ', _nodes_caption);
2114 *_os << "label" << '\t';
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';
2122 std::vector<RedNode> nodes;
2123 for (RedNodeIt n(_graph); n != INVALID; ++n) {
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);
2135 for (int i = 0; i < static_cast<int>(nodes.size()); ++i) {
2136 RedNode n = nodes[i];
2138 std::ostringstream os;
2139 os << _graph.id(static_cast<Node>(n));
2140 _writer_bits::writeToken(*_os, os.str());
2142 _red_node_index.insert(std::make_pair(n, os.str()));
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));
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") {
2167 *_os << "@blue_nodes";
2168 if (!_nodes_caption.empty()) {
2169 _writer_bits::writeToken(*_os << ' ', _nodes_caption);
2174 *_os << "label" << '\t';
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';
2182 std::vector<BlueNode> nodes;
2183 for (BlueNodeIt n(_graph); n != INVALID; ++n) {
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);
2195 for (int i = 0; i < static_cast<int>(nodes.size()); ++i) {
2196 BlueNode n = nodes[i];
2198 std::ostringstream os;
2199 os << _graph.id(static_cast<Node>(n));
2200 _writer_bits::writeToken(*_os, os.str());
2202 _blue_node_index.insert(std::make_pair(n, os.str()));
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));
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") {
2228 for (RedNodeIt n(_graph); n != INVALID; ++n) {
2229 std::ostringstream os;
2231 _red_node_index.insert(std::make_pair(n, os.str()));
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));
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") {
2252 for (BlueNodeIt n(_graph); n != INVALID; ++n) {
2253 std::ostringstream os;
2255 _blue_node_index.insert(std::make_pair(n, os.str()));
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));
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") {
2276 if (!_edges_caption.empty()) {
2277 _writer_bits::writeToken(*_os << ' ', _edges_caption);
2281 *_os << '\t' << '\t';
2283 *_os << "label" << '\t';
2285 for (typename EdgeMaps::iterator it = _edge_maps.begin();
2286 it != _edge_maps.end(); ++it) {
2287 _writer_bits::writeToken(*_os, it->first) << '\t';
2291 std::vector<Edge> edges;
2292 for (EdgeIt n(_graph); n != INVALID; ++n) {
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);
2304 for (int i = 0; i < static_cast<int>(edges.size()); ++i) {
2306 _writer_bits::writeToken(*_os, _red_node_index.
2307 find(_graph.redNode(e))->second);
2309 _writer_bits::writeToken(*_os, _blue_node_index.
2310 find(_graph.blueNode(e))->second);
2313 std::ostringstream os;
2315 _writer_bits::writeToken(*_os, os.str());
2317 _edge_index.insert(std::make_pair(e, os.str()));
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));
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") {
2343 for (EdgeIt e(_graph); e != INVALID; ++e) {
2344 std::ostringstream os;
2346 _edge_index.insert(std::make_pair(e, os.str()));
2349 for (EdgeIt e(_graph); e != INVALID; ++e) {
2350 std::string value = label->get(e);
2351 _edge_index.insert(std::make_pair(e, value));
2356 void writeAttributes() {
2357 if (_attributes.empty()) return;
2358 *_os << "@attributes";
2359 if (!_attributes_caption.empty()) {
2360 _writer_bits::writeToken(*_os << ' ', _attributes_caption);
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());
2373 /// \name Execution of the Writer
2376 /// \brief Start the batch processing
2378 /// This function starts the batch processing.
2384 createRedNodeIndex();
2385 createBlueNodeIndex();
2395 /// \brief Give back the stream of the writer
2397 /// Give back the stream of the writer
2398 std::ostream& ostream() {
2405 /// \ingroup lemon_io
2407 /// \brief Return a \ref lemon::BpGraphWriter "BpGraphWriter" class
2409 /// This function just returns a \ref lemon::BpGraphWriter
2410 /// "BpGraphWriter" class.
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:
2419 ///ListBpGraph graph;
2420 ///ListBpGraph::EdgeMap<int> weight(graph);
2421 /// // Setting the weight map
2422 ///bpGraphWriter(graph, std::cout).
2423 /// edgeMap("weight", weight).
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>
2436 BpGraphWriter<TBGR> bpGraphWriter(const TBGR& graph, std::ostream& os) {
2437 BpGraphWriter<TBGR> tmp(graph, os);
2441 /// \brief Return a \ref BpGraphWriter class
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>
2447 BpGraphWriter<TBGR> bpGraphWriter(const TBGR& graph, const std::string& fn) {
2448 BpGraphWriter<TBGR> tmp(graph, fn);
2452 /// \brief Return a \ref BpGraphWriter class
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>
2458 BpGraphWriter<TBGR> bpGraphWriter(const TBGR& graph, const char* fn) {
2459 BpGraphWriter<TBGR> tmp(graph, fn);
2463 class SectionWriter;
2465 SectionWriter sectionWriter(std::istream& is);
2466 SectionWriter sectionWriter(const std::string& fn);
2467 SectionWriter sectionWriter(const char* fn);
2469 /// \ingroup lemon_io
2471 /// \brief Section writer class
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 {
2486 typedef std::vector<std::pair<std::string, _writer_bits::Section*> >
2493 /// \brief Constructor
2495 /// Construct a section writer, which writes to the given output
2497 SectionWriter(std::ostream& os)
2498 : _os(&os), local_os(false) {}
2500 /// \brief Constructor
2502 /// Construct a section writer, which writes into the given file.
2503 SectionWriter(const std::string& fn)
2504 : _os(new std::ofstream(fn.c_str())), local_os(true) {
2507 throw IoError("Cannot write file", fn);
2511 /// \brief Constructor
2513 /// Construct a section writer, which writes into the given file.
2514 SectionWriter(const char* fn)
2515 : _os(new std::ofstream(fn)), local_os(true) {
2518 throw IoError("Cannot write file", fn);
2522 /// \brief Destructor
2524 for (Sections::iterator it = _sections.begin();
2525 it != _sections.end(); ++it) {
2537 friend SectionWriter sectionWriter(std::ostream& os);
2538 friend SectionWriter sectionWriter(const std::string& fn);
2539 friend SectionWriter sectionWriter(const char* fn);
2541 SectionWriter(SectionWriter& other)
2542 : _os(other._os), local_os(other.local_os) {
2545 other.local_os = false;
2547 _sections.swap(other._sections);
2550 SectionWriter& operator=(const SectionWriter&);
2554 /// \name Section Writers
2557 /// \brief Add a section writer with line oriented writing
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.
2564 /// For example, an integer vector is written into a section.
2572 /// The generator is implemented as a struct.
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++) << ' ';
2585 /// return ls.str();
2591 /// writer.sectionLines("numbers", NumberSection(vec));
2593 template <typename 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)));
2602 /// \brief Add a section writer with stream oriented writing
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>
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)));
2621 /// \name Execution of the Writer
2624 /// \brief Start the batch processing
2626 /// This function starts the batch processing.
2629 LEMON_ASSERT(_os != 0, "This writer is assigned to an other writer");
2631 for (Sections::iterator it = _sections.begin();
2632 it != _sections.end(); ++it) {
2633 (*_os) << '@' << it->first << std::endl;
2634 it->second->process(*_os);
2638 /// \brief Give back the stream of the writer
2640 /// Returns the stream of the writer
2641 std::ostream& ostream() {
2649 /// \ingroup lemon_io
2651 /// \brief Return a \ref SectionWriter class
2653 /// This function just returns a \ref SectionWriter class.
2655 /// Please see SectionWriter documentation about the custom section
2658 /// \relates SectionWriter
2659 /// \sa sectionWriter(const std::string& fn)
2660 /// \sa sectionWriter(const char *fn)
2661 inline SectionWriter sectionWriter(std::ostream& os) {
2662 SectionWriter tmp(os);
2666 /// \brief Return a \ref SectionWriter class
2668 /// This function just returns a \ref SectionWriter class.
2669 /// \relates SectionWriter
2670 /// \sa sectionWriter(std::ostream& os)
2671 inline SectionWriter sectionWriter(const std::string& fn) {
2672 SectionWriter tmp(fn);
2676 /// \brief Return a \ref SectionWriter class
2678 /// This function just returns a \ref SectionWriter class.
2679 /// \relates SectionWriter
2680 /// \sa sectionWriter(std::ostream& os)
2681 inline SectionWriter sectionWriter(const char* fn) {
2682 SectionWriter tmp(fn);