lemon/lemon_writer.h
author deba
Fri, 29 Sep 2006 11:26:29 +0000
changeset 2224 f973894da54e
parent 2101 439b7f21ccc4
child 2260 4274224f8a7d
permissions -rw-r--r--
Moving the file into correct group
     1 /* -*- C++ -*-
     2  *
     3  * This file is a part of LEMON, a generic C++ optimization library
     4  *
     5  * Copyright (C) 2003-2006
     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 Lemon Format writer.
    22 
    23 #ifndef LEMON_LEMON_WRITER_H
    24 #define LEMON_LEMON_WRITER_H
    25 
    26 #include <iostream>
    27 #include <fstream>
    28 #include <string>
    29 #include <vector>
    30 #include <algorithm>
    31 #include <map>
    32 #include <memory>
    33 
    34 #include <lemon/error.h>
    35 #include <lemon/bits/invalid.h>
    36 #include <lemon/graph_utils.h>
    37 #include <lemon/bits/item_writer.h>
    38 #include <lemon/bits/utility.h>
    39 #include <lemon/maps.h>
    40 #include <lemon/dim2.h>
    41 
    42 #include <lemon/concept_check.h>
    43 #include <lemon/concept/maps.h>
    44 
    45 
    46 namespace lemon {
    47 
    48   namespace _writer_bits {
    49     
    50     template <typename T>
    51     bool operator<(T, T) {
    52       throw DataFormatError("Label is not comparable");
    53     }
    54 
    55     template <typename T>
    56     struct Less {
    57       bool operator()(const T& p, const T& q) const {
    58 	return p < q;
    59       }
    60     };
    61 
    62     template <typename Map>
    63     struct ComposeLess {
    64       ComposeLess(const Map& _map) : map(_map), less() {}
    65 
    66       bool operator()(const typename Map::Key& p, 
    67                       const typename Map::Key& q) const {
    68 	return less(map[p], map[q]);
    69       }
    70       const Map& map;
    71       Less<typename Map::Value> less;
    72     };
    73 
    74     template <typename Item>
    75     class ItemLabelWriter {
    76     public:
    77 
    78       bool isLabelWriter() { return true; }
    79 
    80       void writeLabel(std::ostream&, const Item&) {}
    81       
    82       template <class _ItemLabelWriter>
    83       struct Constraints {
    84 	void constraints() {
    85 	  bool b = writer.isLabelWriter();
    86 	  ignore_unused_variable_warning(b);
    87 	  writer.writeLabel(os, item);
    88 	}
    89 	_ItemLabelWriter& writer;
    90 	std::ostream& os;
    91 	const Item& item;
    92       };
    93 
    94     };
    95 
    96     template <typename Item>
    97     class ItemWriter {
    98     public:
    99 
   100       void write(std::ostream&, const Item&) {}
   101       
   102       template <class _ItemWriter>
   103       struct Constraints {
   104 	void constraints() {
   105 	  writer.write(os, item);
   106 	}
   107 	_ItemWriter& writer;
   108 	std::ostream& os;
   109 	const Item& item;
   110       };
   111 
   112     };
   113 
   114     template <typename Map>
   115     struct Ref { typedef const Map& Type; };
   116 
   117     template <typename Graph, typename Map>
   118     class ForwardComposeMap {
   119     public:
   120       typedef typename Graph::UEdge Key;
   121       typedef typename Map::Value Value;
   122 
   123       ForwardComposeMap(const Graph& _graph, const Map& _map) 
   124 	: graph(_graph), map(_map) {}
   125       
   126       Value operator[](const Key& key) {
   127 	return map[graph.direct(key, false)];
   128       }
   129 
   130     private:
   131       typename Ref<Map>::Type map;
   132       const Graph& graph;
   133     };
   134 
   135     template <typename Graph, typename Map>
   136     ForwardComposeMap<Graph, Map>
   137     forwardComposeMap(const Graph& graph, const Map& map) {
   138       return ForwardComposeMap<Graph, Map>(graph, map);
   139     }
   140 
   141     template <typename Graph, typename Map>
   142     class BackwardComposeMap {
   143     public:
   144       typedef typename Graph::UEdge Key;
   145       typedef typename Map::Value Value;
   146 
   147       BackwardComposeMap(const Graph& _graph, const Map& _map) 
   148 	: graph(_graph), map(_map) {}
   149       
   150       Value operator[](const Key& key) {
   151 	return map[graph.direct(key, false)];
   152       }
   153 
   154     private:
   155       typename Ref<Map>::Type map;
   156       const Graph& graph;
   157     };
   158 
   159     template <typename Graph, typename Map>
   160     BackwardComposeMap<Graph, Map>
   161     backwardComposeMap(const Graph& graph, const Map& map) {
   162       return BackwardComposeMap<Graph, Map>(graph, map);
   163     }
   164 
   165     template <typename Graph, typename Map>
   166     struct Ref<ForwardComposeMap<Graph, Map> > { 
   167       typedef ForwardComposeMap<Graph, Map> Type;
   168     };
   169 
   170     template <typename Graph, typename Map>
   171     struct Ref<BackwardComposeMap<Graph, Map> > { 
   172       typedef BackwardComposeMap<Graph, Map> Type; 
   173     };
   174 
   175     template <typename Map>
   176     struct Ref<dim2::XMap<Map> > { 
   177       typedef dim2::XMap<Map> Type;
   178     };
   179     template <typename Map>
   180     struct Ref<dim2::ConstXMap<Map> > { 
   181       typedef dim2::ConstXMap<Map> Type;
   182     };
   183 
   184     template <typename Map>
   185     struct Ref<dim2::YMap<Map> > { 
   186       typedef dim2::YMap<Map> Type;
   187     };
   188     template <typename Map>
   189     struct Ref<dim2::ConstYMap<Map> > { 
   190       typedef dim2::ConstYMap<Map> Type;
   191     };
   192 
   193 
   194     template <typename _Item>    
   195     class MapWriterBase {
   196     public:
   197       typedef _Item Item;
   198 
   199       virtual ~MapWriterBase() {}
   200 
   201       virtual void write(std::ostream& os, const Item& item) const = 0;
   202       virtual void sortByMap(std::vector<Item>&) const = 0;
   203     };
   204 
   205 
   206     template <typename _Item, typename _Map, typename _Writer>
   207     class MapWriter : public MapWriterBase<_Item> {
   208     public:
   209       typedef _Map Map;
   210       typedef _Writer Writer;
   211       typedef typename Writer::Value Value;
   212       typedef _Item Item;
   213       
   214       typename _writer_bits::Ref<Map>::Type map;
   215       Writer writer;
   216 
   217       MapWriter(const Map& _map, const Writer& _writer) 
   218 	: map(_map), writer(_writer) {}
   219 
   220       virtual ~MapWriter() {}
   221 
   222       virtual void write(std::ostream& os, const Item& item) const {
   223 	Value value = map[item];
   224 	writer.write(os, value);
   225       }
   226 
   227       virtual void sortByMap(std::vector<Item>& items) const {
   228         ComposeLess<Map> less(map);
   229         std::sort(items.begin(), items.end(), less);
   230       }
   231 
   232     };
   233 
   234 
   235     class ValueWriterBase {
   236     public:
   237       virtual ~ValueWriterBase() {}
   238       virtual void write(std::ostream&) = 0;
   239     };
   240 
   241     template <typename _Value, typename _Writer>
   242     class ValueWriter : public ValueWriterBase {
   243     public:
   244       typedef _Value Value;
   245       typedef _Writer Writer;
   246 
   247       ValueWriter(const Value& _value, const Writer& _writer)
   248  	: value(_value), writer(_writer) {}
   249 
   250       virtual void write(std::ostream& os) {
   251 	writer.write(os, value);
   252       }
   253     private:
   254       const Value& value;
   255       Writer writer;
   256     };
   257     
   258 
   259     template <typename _Item>
   260     class LabelWriterBase {
   261     public:
   262       typedef _Item Item;
   263       virtual ~LabelWriterBase() {}
   264       virtual void write(std::ostream&, const Item&) const = 0;
   265       virtual bool isLabelWriter() const = 0;
   266     };
   267 
   268     template <typename _Item, typename _BoxedLabelWriter>
   269     class LabelWriter : public LabelWriterBase<_Item> {
   270     public:
   271       typedef _Item Item;
   272       typedef _BoxedLabelWriter BoxedLabelWriter;
   273 
   274       const BoxedLabelWriter& labelWriter;
   275 
   276       LabelWriter(const BoxedLabelWriter& _labelWriter) 
   277 	: labelWriter(_labelWriter) {}
   278 
   279       virtual void write(std::ostream& os, const Item& item) const {
   280 	labelWriter.writeLabel(os, item);
   281       }
   282 
   283       virtual bool isLabelWriter() const {
   284 	return labelWriter.isLabelWriter();
   285       }
   286     };
   287 
   288   }
   289 
   290   /// \ingroup lemon_io
   291   /// \brief Lemon Format writer class.
   292   /// 
   293   /// The Lemon Format contains several sections. We do not want to
   294   /// determine what sections are in a lemon file we give only a framework
   295   /// to write a section oriented format.
   296   ///
   297   /// In the Lemon Format each section starts with a line contains a \c \@
   298   /// character on the first not white space position. This line is the
   299   /// header line of the section. Each next lines belong to this section
   300   /// while it does not starts with \c \@ character. This line can start a 
   301   /// new section or if it can close the file with the \c \@end line.
   302   /// The file format ignore the empty lines and it may contain comments
   303   /// started with a \c # character to the end of the line. 
   304   ///
   305   /// The framework provides an abstract LemonWriter::SectionWriter class
   306   /// what defines the interface of a SectionWriter. The SectionWriter
   307   /// has the \c header() member function what gives back the header of the
   308   /// section. After that it will be called the \c write() member which
   309   /// should write the content of the section.
   310   ///
   311   /// \relates GraphWriter
   312   /// \relates NodeSetWriter
   313   /// \relates EdgeSetWriter
   314   /// \relates NodesWriter
   315   /// \relates EdgesWriter
   316   /// \relates AttributeWriter
   317   class LemonWriter {
   318   public:
   319 
   320     /// \brief Abstract base class for writing a section.
   321     ///
   322     /// This class has an \c header() member function what gives back
   323     /// the header line of the section. The \c write() member should
   324     /// write the content of the section to the stream.
   325     class SectionWriter {
   326       friend class LemonWriter;
   327     protected:
   328       /// \brief Constructor for SectionWriter.
   329       ///
   330       /// Constructor for SectionWriter. It attach this writer to
   331       /// the given LemonWriter.
   332       SectionWriter(LemonWriter& writer) {
   333 	writer.attach(*this);
   334       }
   335       
   336       virtual ~SectionWriter() {}
   337 
   338       /// \brief The header of section.
   339       ///
   340       /// It gives back the header of the section.
   341       virtual std::string header() = 0;
   342 
   343       /// \brief Writer function of the section.
   344       ///
   345       /// Write the content of the section.
   346       virtual void write(std::ostream& os) = 0;
   347       
   348       /// \brief Gives back true when the section should be written.
   349       ///
   350       /// Gives back true when the section should be written.
   351       virtual bool valid() { return true; }
   352     };
   353 
   354     /// \brief Constructor for LemonWriter.
   355     ///
   356     /// Constructor for LemonWriter which writes to the given stream.
   357     LemonWriter(std::ostream& _os) 
   358       : os(&_os), own_os(false) {}
   359 
   360     /// \brief Constructor for LemonWriter.
   361     ///
   362     /// Constructor for LemonWriter which writes to the given file.
   363     LemonWriter(const std::string& filename) 
   364       : os(0), own_os(true) {
   365       os = new std::ofstream(filename.c_str());
   366     }
   367 
   368     /// \brief Desctructor for LemonWriter.
   369     ///
   370     /// Desctructor for LemonWriter.
   371     ~LemonWriter() {
   372       if (own_os) {
   373 	delete os;
   374       }
   375     }
   376 
   377   private:
   378     LemonWriter(const LemonWriter&);
   379     void operator=(const LemonWriter&);
   380 
   381     void attach(SectionWriter& writer) {
   382       writers.push_back(&writer);
   383     }
   384 
   385   public:
   386 
   387     /// \brief Executes the LemonWriter.
   388     /// 
   389     /// It executes the LemonWriter.
   390     void run() {
   391       SectionWriters::iterator it;
   392       for (it = writers.begin(); it != writers.end(); ++it) {
   393         if ((*it)->valid()) {
   394           *os << (*it)->header() << std::endl;
   395           (*it)->write(*os);
   396         }
   397       }
   398       *os << "@end" << std::endl;
   399     }
   400 
   401 
   402   private:
   403 
   404     std::ostream* os;
   405     bool own_os;
   406 
   407     typedef std::vector<SectionWriter*> SectionWriters;
   408     SectionWriters writers;
   409 
   410   };
   411 
   412   /// \ingroup section_io
   413   /// \brief SectionWriter for writing a graph's nodeset.
   414   ///
   415   /// The lemon format can store multiple graph nodesets with several maps.
   416   /// The nodeset section's header line is \c \@nodeset \c nodeset_name, but 
   417   /// the \c nodeset_name may be empty.
   418   ///
   419   /// The first line of the section contains the names of the maps separated
   420   /// with white spaces. Each next lines describes a node in the nodeset, and
   421   /// contains the mapped values for each map.
   422   ///
   423   /// If the nodeset contains an \c "label" named map then it will be regarded
   424   /// as label map. This map should contain only unique values and when the 
   425   /// \c writeLabel() member will be called with a node it will write it's 
   426   /// label. Otherwise if the \c _forceLabelMap constructor parameter is true 
   427   /// then the label map will be the id in the graph. In addition if the
   428   /// the \c _sortByLabel is true then the writer will write the edges
   429   /// sorted by the labels.
   430   ///
   431   /// \relates LemonWriter
   432   template <typename _Graph, typename _Traits = DefaultWriterTraits>
   433   class NodeSetWriter : public LemonWriter::SectionWriter {
   434     typedef LemonWriter::SectionWriter Parent;
   435   public:
   436 
   437     typedef _Graph Graph;
   438     typedef _Traits Traits;
   439     typedef typename Graph::Node Node;
   440 
   441     /// \brief Constructor.
   442     ///
   443     /// Constructor for NodeSetWriter. It creates the NodeSetWriter and
   444     /// attach it into the given LemonWriter. If the \c _forceLabelMap
   445     /// parameter is true then the writer will write own label map when
   446     /// the user does not give "label" named map. In addition if the
   447     /// the \c _sortByLabel is true then the writer will write the edges
   448     /// sorted by the labels.
   449     NodeSetWriter(LemonWriter& _writer, const Graph& _graph, 
   450 		  const std::string& _name = std::string(), 
   451 		  bool _forceLabelMap = true, bool _sortByLabel = true) 
   452       : Parent(_writer), labelMap(0), forceLabelMap(_forceLabelMap), 
   453 	sortByLabel(_sortByLabel), graph(_graph), name(_name) {}
   454 
   455     /// \brief Destructor.
   456     ///
   457     /// Destructor for NodeSetWriter.
   458     virtual ~NodeSetWriter() {
   459       typename MapWriters::iterator it;
   460       for (it = writers.begin(); it != writers.end(); ++it) {
   461 	delete it->second;
   462       }
   463     }
   464 
   465   private:
   466     NodeSetWriter(const NodeSetWriter&);
   467     void operator=(const NodeSetWriter&);
   468   
   469   public:
   470 
   471     /// \brief Add a new node map writer command for the writer.
   472     ///
   473     /// Add a new node map writer command for the writer.
   474     template <typename Map>
   475     NodeSetWriter& writeNodeMap(std::string name, const Map& map) {
   476       return writeNodeMap<typename Traits::
   477 	template Writer<typename Map::Value>, Map>(name, map);
   478     }
   479 
   480     /// \brief Add a new node map writer command for the writer.
   481     ///
   482     /// Add a new node map writer command for the writer.
   483     template <typename Writer, typename Map>
   484     NodeSetWriter& writeNodeMap(std::string name, const Map& map, 
   485 			    const Writer& writer = Writer()) {
   486       checkConcept<concept::ReadMap<Node, typename Map::Value>, Map>();
   487       checkConcept<_writer_bits::ItemWriter<typename Map::Value>, Writer>();
   488       writers.push_back(
   489 	make_pair(name, new _writer_bits::
   490 		  MapWriter<Node, Map, Writer>(map, writer)));
   491       return *this;
   492     }
   493 
   494   protected:
   495 
   496     /// \brief The header of the section.
   497     ///
   498     /// It gives back the header of the section.
   499     virtual std::string header() {
   500       return "@nodeset " + name;
   501     }
   502 
   503     /// \brief  Writer function of the section.
   504     ///
   505     /// Write the content of the section.
   506     virtual void write(std::ostream& os) {
   507       for (int i = 0; i < (int)writers.size(); ++i) {
   508 	if (writers[i].first == "label") {
   509 	  labelMap = writers[i].second;
   510 	  forceLabelMap = false;
   511 	  break;
   512 	}
   513       }
   514       std::vector<Node> items;
   515       for (typename Graph::NodeIt it(graph); it != INVALID; ++it) {
   516         items.push_back(it);
   517       }
   518       if (sortByLabel) {
   519         if (labelMap) {
   520           labelMap->sortByMap(items);
   521         } else {
   522           typedef IdMap<Graph, Node> Map;
   523           Map map(graph);
   524           _writer_bits::ComposeLess<Map> less(map);
   525           std::sort(items.begin(), items.end(), less);
   526         }
   527       }
   528       if (forceLabelMap) {
   529 	os << "label\t";
   530       }
   531       for (int i = 0; i < (int)writers.size(); ++i) {
   532 	os << writers[i].first << '\t';
   533       }
   534       os << std::endl;
   535       for (typename std::vector<Node>::iterator it = items.begin();
   536            it != items.end(); ++it) {
   537 	if (forceLabelMap) {
   538 	  os << graph.id(*it) << '\t';
   539 	}
   540 	for (int i = 0; i < (int)writers.size(); ++i) {
   541 	  writers[i].second->write(os, *it);
   542 	  os << '\t';
   543 	}
   544 	os << std::endl;
   545       }
   546     }
   547 
   548   public:
   549 
   550     /// \brief Returns true if the nodeset can write the labels of the nodes.
   551     ///
   552     /// Returns true if the nodeset can write the labels of the nodes.
   553     /// It is possible only if an "label" named map was written or the 
   554     /// \c _forceLabelMap constructor parameter was true.
   555     bool isLabelWriter() const {
   556       return labelMap != 0 || forceLabelMap;
   557     }
   558 
   559     /// \brief Write the label of the given node.
   560     ///
   561     /// It writes the label of the given node. If there was written an "label"
   562     /// named map then it will write the map value belongs to the node.
   563     /// Otherwise if the \c forceLabel parameter was true it will write
   564     /// its label in the graph. 
   565     void writeLabel(std::ostream& os, const Node& item) const {
   566       if (forceLabelMap) {
   567 	os << graph.id(item);
   568       } else {
   569 	labelMap->write(os, item);
   570       }
   571     }
   572 
   573   private:
   574 
   575     typedef std::vector<std::pair<std::string, _writer_bits::
   576 				  MapWriterBase<Node>*> > MapWriters;
   577     MapWriters writers;
   578 
   579     _writer_bits::MapWriterBase<Node>* labelMap;
   580     bool forceLabelMap;
   581     bool sortByLabel;
   582    
   583     const Graph& graph;   
   584     std::string name;
   585 
   586   };
   587 
   588   /// \ingroup section_io
   589   /// \brief SectionWriter for writing a graph's edgesets.
   590   ///
   591   /// The lemon format can store multiple graph edgesets with several maps. 
   592   /// The edgeset section's header line is \c \@edgeset \c edgeset_name, but 
   593   /// the \c edgeset_name may be empty.
   594   ///
   595   /// The first line of the section contains the names of the maps separated
   596   /// with white spaces. Each next lines describes a edge in the edgeset. The
   597   /// line contains the source and the target nodes' label and the mapped 
   598   /// values for each map.
   599   ///
   600   /// If the edgeset contains an \c "label" named map then it will be regarded
   601   /// as label map. This map should contain only unique values and when the 
   602   /// \c writeLabel() member will be called with an edge it will write it's 
   603   /// label. Otherwise if the \c _forceLabelMap constructor parameter is true 
   604   /// then the label map will be the id in the graph. In addition if the
   605   /// the \c _sortByLabel is true then the writer will write the edges
   606   /// sorted by the labels.
   607   ///
   608   /// The edgeset writer needs a node label writer to identify which nodes
   609   /// have to be connected. If a NodeSetWriter can write the nodes' label,
   610   /// it will be able to use with this class.
   611   ///
   612   /// \relates LemonWriter
   613   template <typename _Graph, typename _Traits = DefaultWriterTraits>
   614   class EdgeSetWriter : public LemonWriter::SectionWriter {
   615     typedef LemonWriter::SectionWriter Parent;
   616   public:
   617 
   618     typedef _Graph Graph;
   619     typedef _Traits Traits;
   620     typedef typename Graph::Node Node;
   621     typedef typename Graph::Edge Edge;
   622 
   623     /// \brief Constructor.
   624     ///
   625     /// Constructor for EdgeSetWriter. It creates the EdgeSetWriter
   626     /// and attach it into the given LemonWriter. It will write node
   627     /// labels by the \c _nodeLabelWriter. If the \c _forceLabelMap
   628     /// parameter is true then the writer will write own label map if
   629     /// the user does not give "label" named map. In addition if the
   630     /// the \c _sortByLabel is true then the writer will write the
   631     /// edges sorted by the labels.
   632     template <typename NodeLabelWriter>
   633     EdgeSetWriter(LemonWriter& _writer, const Graph& _graph, 
   634 		  const NodeLabelWriter& _nodeLabelWriter, 
   635 		  const std::string& _name = std::string(),
   636 		  bool _forceLabelMap = true, bool _sortByLabel = true)
   637       : Parent(_writer), labelMap(0), forceLabelMap(_forceLabelMap),
   638 	sortByLabel(_sortByLabel), graph(_graph), name(_name) {
   639       checkConcept<_writer_bits::ItemLabelWriter<Node>, NodeLabelWriter>();
   640       nodeLabelWriter.reset(new _writer_bits::
   641 			 LabelWriter<Node, NodeLabelWriter>(_nodeLabelWriter));
   642     } 
   643 
   644     /// \brief Destructor.
   645     ///
   646     /// Destructor for EdgeSetWriter.
   647     virtual ~EdgeSetWriter() {
   648       typename MapWriters::iterator it;
   649       for (it = writers.begin(); it != writers.end(); ++it) {
   650 	delete it->second;
   651       }
   652     }
   653 
   654   private:
   655     EdgeSetWriter(const EdgeSetWriter&);
   656     void operator=(const EdgeSetWriter&);
   657 
   658   public:
   659 
   660     /// \brief Add a new edge map writer command for the writer.
   661     ///
   662     /// Add a new edge map writer command for the writer.
   663     template <typename Map>
   664     EdgeSetWriter& writeEdgeMap(std::string name, const Map& map) {
   665       return writeEdgeMap<typename Traits::
   666 	template Writer<typename Map::Value>, Map>(name, map);
   667     }
   668 
   669     /// \brief Add a new edge map writer command for the writer.
   670     ///
   671     /// Add a new edge map writer command for the writer.
   672     template <typename Writer, typename Map>
   673     EdgeSetWriter& writeEdgeMap(std::string name, const Map& map, 
   674 			    const Writer& writer = Writer()) {
   675       checkConcept<concept::ReadMap<Edge, typename Map::Value>, Map>();
   676       checkConcept<_writer_bits::ItemWriter<typename Map::Value>, Writer>();
   677       writers.push_back(
   678 	make_pair(name, new _writer_bits::
   679 		  MapWriter<Edge, Map, Writer>(map, writer)));
   680       return *this;
   681     }
   682 
   683   protected:
   684 
   685     /// \brief The header of the section.
   686     ///
   687     /// It gives back the header of the section.
   688     virtual std::string header() {
   689       return "@edgeset " + name;
   690     }
   691 
   692     /// \brief  Writer function of the section.
   693     ///
   694     /// Write the content of the section.
   695     virtual void write(std::ostream& os) {
   696       if (!nodeLabelWriter->isLabelWriter()) {
   697 	throw DataFormatError("Cannot find nodeset or label map");
   698       }
   699       for (int i = 0; i < (int)writers.size(); ++i) {
   700 	if (writers[i].first == "label") {
   701 	  labelMap = writers[i].second;
   702 	  forceLabelMap = false;
   703 	  break;
   704 	}
   705       }
   706       std::vector<Edge> items;
   707       for (typename Graph::EdgeIt it(graph); it != INVALID; ++it) {
   708         items.push_back(it);
   709       }
   710       if (sortByLabel) {
   711         if (labelMap) {
   712           labelMap->sortByMap(items);
   713         } else {
   714           typedef IdMap<Graph, Edge> Map;
   715           Map map(graph);
   716           _writer_bits::ComposeLess<Map> less(map);
   717           std::sort(items.begin(), items.end(), less);
   718         }
   719       }
   720       os << "\t\t";
   721       if (forceLabelMap) {
   722 	os << "label\t";
   723       }
   724       for (int i = 0; i < (int)writers.size(); ++i) {
   725 	os << writers[i].first << '\t';
   726       }
   727       os << std::endl;
   728       for (typename std::vector<Edge>::iterator it = items.begin();
   729            it != items.end(); ++it) {
   730 	nodeLabelWriter->write(os, graph.source(*it));
   731 	os << '\t';
   732 	nodeLabelWriter->write(os, graph.target(*it));
   733 	os << '\t';
   734 	if (forceLabelMap) {
   735 	  os << graph.id(*it) << '\t';
   736 	}
   737 	for (int i = 0; i < (int)writers.size(); ++i) {
   738 	  writers[i].second->write(os, *it);
   739 	  os << '\t';
   740 	}
   741 	os << std::endl;
   742       }
   743     }
   744 
   745   public:
   746 
   747     /// \brief Returns true if the edgeset can write the labels of the edges.
   748     ///
   749     /// Returns true if the edgeset can write the labels of the edges.
   750     /// It is possible only if an "label" named map was written or the 
   751     /// \c _forceLabelMap constructor parameter was true.
   752     bool isLabelWriter() const {
   753       return forceLabelMap || labelMap != 0;
   754     }
   755 
   756     /// \brief Write the label of the given edge.
   757     ///
   758     /// It writes the label of the given edge. If there was written an "label"
   759     /// named map then it will write the map value belongs to the edge.
   760     /// Otherwise if the \c forceLabel parameter was true it will write
   761     /// its label in the graph. 
   762     void writeLabel(std::ostream& os, const Edge& item) const {
   763       if (forceLabelMap) {
   764 	os << graph.id(item);
   765       } else {
   766 	labelMap->write(os, item);
   767       }
   768     } 
   769 
   770   private:
   771 
   772     typedef std::vector<std::pair<std::string, _writer_bits::
   773 				  MapWriterBase<Edge>*> > MapWriters;
   774     MapWriters writers;
   775 
   776     _writer_bits::MapWriterBase<Edge>* labelMap;
   777     bool forceLabelMap;
   778     bool sortByLabel;
   779    
   780     const Graph& graph;   
   781     std::string name;
   782 
   783     std::auto_ptr<_writer_bits::LabelWriterBase<Node> > nodeLabelWriter;
   784   };
   785 
   786   /// \ingroup section_io
   787   /// \brief SectionWriter for writing a undirected edgeset.
   788   ///
   789   /// The lemon format can store multiple undirected edgesets with several 
   790   /// maps. The undirected edgeset section's header line is \c \@uedgeset 
   791   /// \c uedgeset_name, but the \c uedgeset_name may be empty.
   792   ///
   793   /// The first line of the section contains the names of the maps separated
   794   /// with white spaces. Each next lines describes an undirected edge in the 
   795   /// edgeset. The line contains the two connected nodes' label and the mapped 
   796   /// values for each undirected map.
   797   ///
   798   /// The section can handle the directed as a syntactical sugar. Two
   799   /// undirected edge map describes one directed edge map. This two maps
   800   /// are the forward map and the backward map and the names of this map
   801   /// is near the same just with a prefix \c '+' or \c '-' character 
   802   /// difference.
   803   ///
   804   /// If the edgeset contains an \c "label" named map then it will be
   805   /// regarded as label map. This map should contain only unique
   806   /// values and when the \c writeLabel() member will be called with
   807   /// an undirected edge it will write it's label. Otherwise if the \c
   808   /// _forceLabelMap constructor parameter is true then the label map
   809   /// will be the id in the graph.  In addition if the the \c
   810   /// _sortByLabel is true then the writer will write the edges sorted
   811   /// by the labels.
   812   ///
   813   /// The undirected edgeset writer needs a node label writer to identify 
   814   /// which nodes have to be connected. If a NodeSetWriter can write the 
   815   /// nodes' label, it will be able to use with this class.
   816   ///
   817   /// \relates LemonWriter
   818   template <typename _Graph, typename _Traits = DefaultWriterTraits>
   819   class UEdgeSetWriter : public LemonWriter::SectionWriter {
   820     typedef LemonWriter::SectionWriter Parent;
   821   public:
   822 
   823     typedef _Graph Graph;
   824     typedef _Traits Traits;
   825     typedef typename Graph::Node Node;
   826     typedef typename Graph::Edge Edge;
   827     typedef typename Graph::UEdge UEdge;
   828 
   829     /// \brief Constructor.
   830     ///
   831     /// Constructor for UEdgeSetWriter. It creates the UEdgeSetWriter
   832     /// and attach it into the given LemonWriter. It will write node
   833     /// labels by the \c _nodeLabelWriter. If the \c _forceLabelMap
   834     /// parameter is true then the writer will write own label map if
   835     /// the user does not give "label" named map. In addition if the
   836     /// the \c _sortByLabel is true then the writer will write the
   837     /// edges sorted by the labels.
   838     template <typename NodeLabelWriter>
   839     UEdgeSetWriter(LemonWriter& _writer, const Graph& _graph, 
   840 		       const NodeLabelWriter& _nodeLabelWriter, 
   841 		       const std::string& _name = std::string(),
   842 		       bool _forceLabelMap = true, bool _sortByLabel = true)
   843       : Parent(_writer), labelMap(0), forceLabelMap(_forceLabelMap),
   844 	sortByLabel(_sortByLabel), graph(_graph), name(_name) {
   845       checkConcept<_writer_bits::ItemLabelWriter<Node>, NodeLabelWriter>();
   846       nodeLabelWriter.reset(new _writer_bits::
   847 			 LabelWriter<Node, NodeLabelWriter>(_nodeLabelWriter));
   848     } 
   849 
   850     /// \brief Destructor.
   851     ///
   852     /// Destructor for UEdgeSetWriter.
   853     virtual ~UEdgeSetWriter() {
   854       typename MapWriters::iterator it;
   855       for (it = writers.begin(); it != writers.end(); ++it) {
   856 	delete it->second;
   857       }
   858     }
   859 
   860   private:
   861     UEdgeSetWriter(const UEdgeSetWriter&);
   862     void operator=(const UEdgeSetWriter&);
   863 
   864   public:
   865 
   866     /// \brief Add a new undirected edge map writer command for the writer.
   867     ///
   868     /// Add a new undirected map writer command for the writer.
   869     template <typename Map>
   870     UEdgeSetWriter& writeUEdgeMap(std::string name, const Map& map) {
   871       return writeUEdgeMap<typename Traits::
   872 	template Writer<typename Map::Value>, Map>(name, map);
   873     }
   874 
   875     /// \brief Add a new undirected map writer command for the writer.
   876     ///
   877     /// Add a new undirected map writer command for the writer.
   878     template <typename Writer, typename Map>
   879     UEdgeSetWriter& writeUEdgeMap(std::string name, const Map& map, 
   880 					  const Writer& writer = Writer()) {
   881       checkConcept<concept::ReadMap<UEdge, typename Map::Value>, Map>();
   882       checkConcept<_writer_bits::ItemWriter<typename Map::Value>, Writer>();
   883       writers.push_back(
   884 	make_pair(name, new _writer_bits::
   885 		  MapWriter<UEdge, Map, Writer>(map, writer)));
   886       return *this;
   887     }
   888 
   889     /// \brief Add a new directed edge map writer command for the writer.
   890     ///
   891     /// Add a new directed map writer command for the writer.
   892     template <typename Map>
   893     UEdgeSetWriter& writeEdgeMap(std::string name, const Map& map) {
   894       return writeEdgeMap<typename Traits::
   895 	template Writer<typename Map::Value>, Map>(name, map);
   896     }
   897 
   898     /// \brief Add a new directed map writer command for the writer.
   899     ///
   900     /// Add a new directed map writer command for the writer.
   901     template <typename Writer, typename Map>
   902     UEdgeSetWriter& writeEdgeMap(std::string name, const Map& map, 
   903 				     const Writer& writer = Writer()) {
   904       checkConcept<concept::ReadMap<Edge, typename Map::Value>, Map>();
   905       checkConcept<_writer_bits::ItemWriter<typename Map::Value>, Writer>();
   906       writeUEdge("+" + name, 
   907 		     _writer_bits::forwardComposeMap(graph, map), writer);
   908       writeUEdge("-" + name, 
   909 		     _writer_bits::backwardComposeMap(graph, map), writer);
   910       return *this;
   911     }
   912 
   913   protected:
   914 
   915     /// \brief The header of the section.
   916     ///
   917     /// It gives back the header of the section.
   918     virtual std::string header() {
   919       return "@uedgeset " + name;
   920     }
   921 
   922     /// \brief  Writer function of the section.
   923     ///
   924     /// Write the content of the section.
   925     virtual void write(std::ostream& os) {
   926       if (!nodeLabelWriter->isLabelWriter()) {
   927 	throw DataFormatError("Cannot find nodeset or label map");
   928       }
   929       for (int i = 0; i < (int)writers.size(); ++i) {
   930 	if (writers[i].first == "label") {
   931 	  labelMap = writers[i].second;
   932 	  forceLabelMap = false;
   933 	  break;
   934 	}
   935       }
   936       std::vector<UEdge> items;
   937       for (typename Graph::UEdgeIt it(graph); it != INVALID; ++it) {
   938         items.push_back(it);
   939       }
   940       if (sortByLabel) {
   941         if (labelMap) {
   942           labelMap->sortByMap(items);
   943         } else {
   944           typedef IdMap<Graph, UEdge> Map;
   945           Map map(graph);
   946           _writer_bits::ComposeLess<Map> less(map);
   947           std::sort(items.begin(), items.end(), less);
   948         }
   949       }
   950       os << "\t\t";
   951       if (forceLabelMap) {
   952 	os << "label\t";
   953       }
   954       for (int i = 0; i < (int)writers.size(); ++i) {
   955 	os << writers[i].first << '\t';
   956       }
   957       os << std::endl;
   958       for (typename std::vector<Edge>::iterator it = items.begin();
   959            it != items.end(); ++it) {
   960 	nodeLabelWriter->write(os, graph.source(*it));
   961 	os << '\t';
   962 	nodeLabelWriter->write(os, graph.target(*it));
   963 	os << '\t';
   964 	if (forceLabelMap) {
   965 	  os << graph.id(*it) << '\t';
   966 	}
   967 	for (int i = 0; i < (int)writers.size(); ++i) {
   968 	  writers[i].second->write(os, *it);
   969 	  os << '\t';
   970 	}
   971 	os << std::endl;
   972       }
   973     }
   974 
   975   public:
   976 
   977     /// \brief Returns true if the undirected edgeset can write the labels of 
   978     /// the edges.
   979     ///
   980     /// Returns true if the undirected edgeset can write the labels of the 
   981     /// undirected edges. It is possible only if an "label" named map was 
   982     /// written or the \c _forceLabelMap constructor parameter was true.
   983     bool isLabelWriter() const {
   984       return forceLabelMap || labelMap != 0;
   985     }
   986 
   987     /// \brief Write the label of the given undirected edge.
   988     ///
   989     /// It writes the label of the given undirected edge. If there was written 
   990     /// an "label" named map then it will write the map value belongs to the 
   991     /// undirected edge. Otherwise if the \c forceLabel parameter was true it 
   992     /// will write its id in the graph. 
   993     void writeLabel(std::ostream& os, const UEdge& item) const {
   994       if (forceLabelMap) {
   995 	os << graph.id(item);
   996       } else {
   997 	labelMap->write(os, item);
   998       }
   999     } 
  1000 
  1001     /// \brief Write the label of the given edge.
  1002     ///
  1003     /// It writes the label of the given edge. If there was written 
  1004     /// an "label" named map then it will write the map value belongs to the 
  1005     /// edge. Otherwise if the \c forceLabel parameter was true it 
  1006     /// will write its id in the graph. If the edge is forward map
  1007     /// then its prefix character is \c '+' elsewhere \c '-'.
  1008     void writeLabel(std::ostream& os, const Edge& item) const {
  1009       if (graph.direction(item)) {
  1010 	os << "+ ";
  1011       } else {
  1012 	os << "- ";
  1013       }
  1014       if (forceLabelMap) {
  1015 	os << graph.id(item);
  1016       } else {
  1017 	labelMap->write(os, item);
  1018       }
  1019     } 
  1020 
  1021   private:
  1022 
  1023     typedef std::vector<std::pair<std::string, _writer_bits::
  1024 				  MapWriterBase<UEdge>*> > MapWriters;
  1025     MapWriters writers;
  1026 
  1027     _writer_bits::MapWriterBase<UEdge>* labelMap;
  1028     bool forceLabelMap;
  1029     bool sortByLabel;
  1030    
  1031     const Graph& graph;   
  1032     std::string name;
  1033 
  1034     std::auto_ptr<_writer_bits::LabelWriterBase<Node> > nodeLabelWriter;
  1035   };
  1036 
  1037   /// \ingroup section_io
  1038   /// \brief SectionWriter for writing named nodes.
  1039   ///
  1040   /// The nodes section's header line is \c \@nodes \c nodes_name, but the
  1041   /// \c nodes_name may be empty.
  1042   ///
  1043   /// Each line in the section contains the name of the node and 
  1044   /// then the node label. 
  1045   ///
  1046   /// \relates LemonWriter
  1047   template <typename _Graph>
  1048   class NodeWriter : public LemonWriter::SectionWriter {
  1049     typedef LemonWriter::SectionWriter Parent;
  1050     typedef _Graph Graph;
  1051     typedef typename Graph::Node Node;
  1052   public:
  1053     
  1054     /// \brief Constructor.
  1055     ///
  1056     /// Constructor for NodeWriter. It creates the NodeWriter and
  1057     /// attach it into the given LemonWriter. The given \c _LabelWriter
  1058     /// will write the nodes' label what can be a nodeset writer.
  1059     template <typename _LabelWriter>
  1060     NodeWriter(LemonWriter& _writer, const _LabelWriter& _labelWriter, 
  1061 	       const std::string& _name = std::string()) 
  1062       : Parent(_writer), name(_name) {
  1063       checkConcept<_writer_bits::ItemLabelWriter<Node>, _LabelWriter>();
  1064       labelWriter.reset(new _writer_bits::LabelWriter<Node, _LabelWriter>
  1065                         (_labelWriter));
  1066     }
  1067 
  1068 
  1069     /// \brief Destructor.
  1070     ///
  1071     /// Destructor for NodeWriter.
  1072     virtual ~NodeWriter() {}
  1073 
  1074   private:
  1075     NodeWriter(const NodeWriter&);
  1076     void operator=(const NodeWriter&);
  1077 
  1078   public:
  1079 
  1080     /// \brief Add a node writer command for the NodeWriter.
  1081     ///
  1082     /// Add a node writer command for the NodeWriter.
  1083     void writeNode(const std::string& name, const Node& item) {
  1084       writers.push_back(make_pair(name, &item));
  1085     }
  1086 
  1087   protected:
  1088 
  1089     /// \brief The header of the section.
  1090     ///
  1091     /// It gives back the header of the section.
  1092     virtual std::string header() {
  1093       return "@nodes " + name;
  1094     }
  1095 
  1096     /// \brief  Writer function of the section.
  1097     ///
  1098     /// Write the content of the section.
  1099     virtual void write(std::ostream& os) {
  1100       if (!labelWriter->isLabelWriter()) {
  1101 	throw DataFormatError("Cannot find nodeset or label map");
  1102       }
  1103       for (int i = 0; i < (int)writers.size(); ++i) {
  1104 	os << writers[i].first << ' ';
  1105 	labelWriter->write(os, *(writers[i].second));
  1106 	os << std::endl;
  1107       }
  1108     }
  1109 
  1110     /// \brief Gives back true when the section should be written.
  1111     ///
  1112     /// Gives back true when the section should be written.
  1113     virtual bool valid() { return !writers.empty(); }
  1114     
  1115   private:
  1116 
  1117     std::string name;
  1118 
  1119     typedef std::vector<std::pair<std::string, const Node*> > NodeWriters;
  1120     NodeWriters writers;
  1121     std::auto_ptr<_writer_bits::LabelWriterBase<Node> > labelWriter;
  1122   };
  1123 
  1124   /// \ingroup section_io
  1125   /// \brief SectionWriter for writing named edges.
  1126   ///
  1127   /// The edges section's header line is \c \@edges \c edges_name, but the
  1128   /// \c edges_name may be empty.
  1129   ///
  1130   /// Each line in the section contains the name of the edge and 
  1131   /// then the edge label. 
  1132   ///
  1133   /// \relates LemonWriter
  1134   template <typename _Graph>
  1135   class EdgeWriter : public LemonWriter::SectionWriter {
  1136     typedef LemonWriter::SectionWriter Parent;
  1137     typedef _Graph Graph;
  1138     typedef typename Graph::Edge Edge;
  1139   public:
  1140     
  1141     /// \brief Constructor.
  1142     ///
  1143     /// Constructor for EdgeWriter. It creates the EdgeWriter and
  1144     /// attach it into the given LemonWriter. The given \c _LabelWriter
  1145     /// will write the edges' label what can be a edgeset writer.
  1146     template <typename _LabelWriter>
  1147     EdgeWriter(LemonWriter& _writer, const _LabelWriter& _labelWriter, 
  1148 	       const std::string& _name = std::string()) 
  1149       : Parent(_writer), name(_name) {
  1150       checkConcept<_writer_bits::ItemLabelWriter<Edge>, _LabelWriter>();
  1151       labelWriter.reset(new _writer_bits::LabelWriter<Edge, _LabelWriter>(_labelWriter));
  1152     }
  1153 
  1154     /// \brief Destructor.
  1155     ///
  1156     /// Destructor for EdgeWriter.
  1157     virtual ~EdgeWriter() {}
  1158   private:
  1159     EdgeWriter(const EdgeWriter&);
  1160     void operator=(const EdgeWriter&);
  1161 
  1162   public:
  1163 
  1164     /// \brief Add an edge writer command for the EdgeWriter.
  1165     ///
  1166     /// Add an edge writer command for the EdgeWriter.
  1167     void writeEdge(const std::string& name, const Edge& item) {
  1168       writers.push_back(make_pair(name, &item));
  1169     }
  1170 
  1171   protected:
  1172 
  1173     /// \brief The header of the section.
  1174     ///
  1175     /// It gives back the header of the section.
  1176     virtual std::string header() {
  1177       return "@edges " + name;
  1178     }
  1179 
  1180     /// \brief  Writer function of the section.
  1181     ///
  1182     /// Write the content of the section.
  1183     virtual void write(std::ostream& os) {
  1184       if (!labelWriter->isLabelWriter()) {
  1185 	throw DataFormatError("Cannot find edgeset or label map");
  1186       }
  1187       for (int i = 0; i < (int)writers.size(); ++i) {
  1188 	os << writers[i].first << ' ';
  1189 	labelWriter->write(os, *(writers[i].second));
  1190 	os << std::endl;
  1191       }
  1192     }
  1193 
  1194     /// \brief Gives back true when the section should be written.
  1195     ///
  1196     /// Gives back true when the section should be written.
  1197     virtual bool valid() { return !writers.empty(); }
  1198     
  1199   private:
  1200 
  1201     std::string name;
  1202 
  1203     typedef std::vector<std::pair<std::string, const Edge*> > EdgeWriters;
  1204     EdgeWriters writers;
  1205 
  1206     std::auto_ptr<_writer_bits::LabelWriterBase<Edge> > labelWriter;
  1207   };
  1208 
  1209   /// \ingroup section_io
  1210   /// \brief SectionWriter for writing named undirected edges.
  1211   ///
  1212   /// The undirected edges section's header line is \c \@uedges 
  1213   /// \c uedges_name, but the \c uedges_name may be empty.
  1214   ///
  1215   /// Each line in the section contains the name of the undirected edge and 
  1216   /// then the undirected edge label. 
  1217   ///
  1218   /// \relates LemonWriter
  1219   template <typename _Graph>
  1220   class UEdgeWriter : public LemonWriter::SectionWriter {
  1221     typedef LemonWriter::SectionWriter Parent;
  1222     typedef _Graph Graph;
  1223     typedef typename Graph::Node Node;
  1224     typedef typename Graph::Edge Edge;
  1225     typedef typename Graph::UEdge UEdge;
  1226   public:
  1227     
  1228     /// \brief Constructor.
  1229     ///
  1230     /// Constructor for UEdgeWriter. It creates the UEdgeWriter and
  1231     /// attach it into the given LemonWriter. The given \c _LabelWriter
  1232     /// will write the undirected edges' label what can be an undirected 
  1233     /// edgeset writer.
  1234     template <typename _LabelWriter>
  1235     UEdgeWriter(LemonWriter& _writer, const _LabelWriter& _labelWriter, 
  1236 	       const std::string& _name = std::string()) 
  1237       : Parent(_writer), name(_name) {
  1238       checkConcept<_writer_bits::ItemLabelWriter<Edge>, _LabelWriter>();
  1239       checkConcept<_writer_bits::ItemLabelWriter<UEdge>, _LabelWriter>();
  1240       uEdgeLabelWriter.reset(new _writer_bits::
  1241 			      LabelWriter<UEdge, _LabelWriter>(_labelWriter));
  1242       edgeLabelWriter.reset(new _writer_bits::
  1243 			 LabelWriter<Edge, _LabelWriter>(_labelWriter));
  1244     }
  1245 
  1246     /// \brief Destructor.
  1247     ///
  1248     /// Destructor for UEdgeWriter.
  1249     virtual ~UEdgeWriter() {}
  1250   private:
  1251     UEdgeWriter(const UEdgeWriter&);
  1252     void operator=(const UEdgeWriter&);
  1253 
  1254   public:
  1255 
  1256     /// \brief Add an edge writer command for the UEdgeWriter.
  1257     ///
  1258     /// Add an edge writer command for the UEdgeWriter.
  1259     void writeEdge(const std::string& name, const Edge& item) {
  1260       edgeWriters.push_back(make_pair(name, &item));
  1261     }
  1262 
  1263     /// \brief Add an undirected edge writer command for the UEdgeWriter.
  1264     ///
  1265     /// Add an undirected edge writer command for the UEdgeWriter.
  1266     void writeUEdge(const std::string& name, const UEdge& item) {
  1267       uEdgeWriters.push_back(make_pair(name, &item));
  1268     }
  1269 
  1270   protected:
  1271 
  1272     /// \brief The header of the section.
  1273     ///
  1274     /// It gives back the header of the section.
  1275     virtual std::string header() {
  1276       return "@uedges " + name;
  1277     }
  1278 
  1279     /// \brief  Writer function of the section.
  1280     ///
  1281     /// Write the content of the section.
  1282     virtual void write(std::ostream& os) {
  1283       if (!edgeLabelWriter->isLabelWriter()) {
  1284 	throw DataFormatError("Cannot find undirected edgeset or label map");
  1285       }
  1286       if (!uEdgeLabelWriter->isLabelWriter()) {
  1287 	throw DataFormatError("Cannot find undirected edgeset or label map");
  1288       }
  1289       for (int i = 0; i < (int)uEdgeWriters.size(); ++i) {
  1290 	os << uEdgeWriters[i].first << ' ';
  1291 	uEdgeLabelWriter->write(os, *(uEdgeWriters[i].second));
  1292 	os << std::endl;
  1293       }
  1294       for (int i = 0; i < (int)edgeWriters.size(); ++i) {
  1295 	os << edgeWriters[i].first << ' ';
  1296 	edgeLabelWriter->write(os, *(edgeWriters[i].second));
  1297 	os << std::endl;
  1298       }
  1299     }
  1300 
  1301     /// \brief Gives back true when the section should be written.
  1302     ///
  1303     /// Gives back true when the section should be written.
  1304     virtual bool valid() { 
  1305       return !uEdgeWriters.empty() || !edgeWriters.empty(); 
  1306     }
  1307     
  1308   private:
  1309 
  1310     std::string name;
  1311 
  1312     typedef std::vector<std::pair<std::string, 
  1313 				  const UEdge*> > UEdgeWriters;
  1314     UEdgeWriters uEdgeWriters;
  1315     std::auto_ptr<_writer_bits::LabelWriterBase<UEdge> > uEdgeLabelWriter;
  1316 
  1317     typedef std::vector<std::pair<std::string, const Edge*> > EdgeWriters;
  1318     EdgeWriters edgeWriters;
  1319     std::auto_ptr<_writer_bits::LabelWriterBase<Edge> > edgeLabelWriter;
  1320 
  1321   };
  1322 
  1323   /// \ingroup section_io
  1324   /// \brief SectionWriter for attributes.
  1325   ///
  1326   /// The lemon format can store multiple attribute set. Each set has
  1327   /// the header line \c \@attributes \c attributes_name, but the 
  1328   /// attributeset_name may be empty.
  1329   ///
  1330   /// The attributeset section contains several lines. Each of them starts
  1331   /// with the name of attribute and then the value.
  1332   ///
  1333   /// \relates LemonWriter
  1334   template <typename _Traits = DefaultWriterTraits>
  1335   class AttributeWriter : public LemonWriter::SectionWriter {
  1336     typedef LemonWriter::SectionWriter Parent;
  1337     typedef _Traits Traits; 
  1338   public:
  1339     /// \brief Constructor.
  1340     ///
  1341     /// Constructor for AttributeWriter. It creates the AttributeWriter and
  1342     /// attach it into the given LemonWriter.
  1343     AttributeWriter(LemonWriter& _writer, 
  1344 		    const std::string& _name = std::string()) 
  1345       : Parent(_writer), name(_name) {}
  1346 
  1347     /// \brief Destructor.
  1348     ///
  1349     /// Destructor for AttributeWriter.
  1350     virtual ~AttributeWriter() {
  1351       typename Writers::iterator it;
  1352       for (it = writers.begin(); it != writers.end(); ++it) {
  1353 	delete it->second;
  1354       }
  1355     }
  1356 
  1357   private:
  1358     AttributeWriter(const AttributeWriter&);
  1359     void operator=(AttributeWriter&);
  1360 
  1361   public:
  1362     /// \brief Add an attribute writer command for the writer.
  1363     ///
  1364     /// Add an attribute writer command for the writer.
  1365     template <typename Value>
  1366     AttributeWriter& writeAttribute(const std::string& name, 
  1367 				    const Value& value) {
  1368       return 
  1369 	writeAttribute<typename Traits::template Writer<Value> >(name, value);
  1370     }
  1371 
  1372     /// \brief Add an attribute writer command for the writer.
  1373     ///
  1374     /// Add an attribute writer command for the writer.
  1375     template <typename Writer, typename Value>
  1376     AttributeWriter& writeAttribute(const std::string& name, 
  1377 				    const Value& value,
  1378 				    const Writer& writer = Writer()) {
  1379       checkConcept<_writer_bits::ItemWriter<Value>, Writer>();
  1380       writers.push_back(make_pair(name, new _writer_bits::
  1381 				  ValueWriter<Value, Writer>(value, writer)));
  1382       return *this;
  1383     }
  1384 
  1385   protected:
  1386 
  1387     /// \brief The header of section.
  1388     ///
  1389     /// It gives back the header of the section.
  1390     std::string header() {
  1391       return "@attributes " + name;
  1392     }
  1393 
  1394     /// \brief  Writer function of the section.
  1395     ///
  1396     /// Write the content of the section.
  1397     void write(std::ostream& os) {
  1398       typename Writers::iterator it;
  1399       for (it = writers.begin(); it != writers.end(); ++it) {
  1400 	os << it->first << ' ';
  1401 	it->second->write(os);
  1402 	os << std::endl;
  1403       }
  1404     }    
  1405 
  1406     /// \brief Gives back true when the section should be written.
  1407     ///
  1408     /// Gives back true when the section should be written.
  1409     virtual bool valid() { return !writers.empty(); }
  1410 
  1411   private:
  1412     std::string name;
  1413 
  1414     typedef std::vector<std::pair<std::string, 
  1415 				  _writer_bits::ValueWriterBase*> > Writers;
  1416     Writers writers;  
  1417   };
  1418 
  1419 
  1420 }
  1421 #endif