src/lemon/lemon_writer.h
author deba
Wed, 11 May 2005 13:49:17 +0000
changeset 1411 5d161e08bda8
parent 1409 d2d1f8fa187b
child 1421 7a21e1414c38
permissions -rw-r--r--
Bug fix.
     1 /* -*- C++ -*-
     2  * src/lemon/lemon_writer.h - Part of LEMON, a generic C++ optimization library
     3  *
     4  * Copyright (C) 2005 Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
     5  * (Egervary Research Group on Combinatorial Optimization, EGRES).
     6  *
     7  * Permission to use, modify and distribute this software is granted
     8  * provided that this copyright notice appears in all copies. For
     9  * precise terms see the accompanying LICENSE file.
    10  *
    11  * This software is provided "AS IS" with no warranty of any kind,
    12  * express or implied, and with no claim as to its suitability for any
    13  * purpose.
    14  *
    15  */
    16 
    17 ///\ingroup io_group
    18 ///\file
    19 ///\brief Lemon Format writer.
    20 
    21 #ifndef LEMON_LEMON_WRITER_H
    22 #define LEMON_LEMON_WRITER_H
    23 
    24 #include <iostream>
    25 #include <fstream>
    26 #include <string>
    27 #include <vector>
    28 #include <algorithm>
    29 #include <map>
    30 #include <memory>
    31 
    32 #include <lemon/error.h>
    33 #include <lemon/invalid.h>
    34 #include <lemon/bits/item_writer.h>
    35 
    36 
    37 namespace lemon {
    38 
    39   /// \ingroup io_group
    40   /// \brief Lemon Format writer class.
    41   /// 
    42   /// The Lemon Format contains several sections. We do not want to
    43   /// determine what sections are in a lemon file we give only a framework
    44   /// to write a section oriented format.
    45   ///
    46   /// In the Lemon Format each section starts with a line contains a \c \@
    47   /// character on the first not white space position. This line is the
    48   /// header line of the section. Each next lines belong to this section
    49   /// while it does not starts with \c \@ character. This line can start a 
    50   /// new section or if it can close the file with the \c \@end line.
    51   /// The file format ignore the empty lines and it may contain comments
    52   /// started with a \c # character to the end of the line. 
    53   ///
    54   /// The framework provides an abstract LemonWriter::SectionWriter class
    55   /// what defines the interface of a SectionWriter. The SectionWriter
    56   /// has the \c header() member function what gives back the header of the
    57   /// section. After that it will be called the \c write() member which
    58   /// should write the content of the section.
    59   ///
    60   /// \relates GraphWriter
    61   /// \relates NodeSetWriter
    62   /// \relates EdgeSetWriter
    63   /// \relates NodesWriter
    64   /// \relates EdgesWriter
    65   /// \relates AttributeWriter
    66   class LemonWriter {
    67   public:
    68 
    69     /// \brief Abstract base class for writing a section.
    70     ///
    71     /// This class has an \c header() member function what gives back
    72     /// the header line of the section. The \c write() member should
    73     /// write the content of the section to the stream.
    74     class SectionWriter {
    75       friend class LemonWriter;
    76     protected:
    77       /// \brief Constructor for SectionWriter.
    78       ///
    79       /// Constructor for SectionWriter. It attach this writer to
    80       /// the given LemonWriter.
    81       SectionWriter(LemonWriter& writer) {
    82 	writer.attach(*this);
    83       }
    84 
    85       /// \brief The header of section.
    86       ///
    87       /// It gives back the header of the section.
    88       virtual std::string header() = 0;
    89 
    90       /// \brief  Writer function of the section.
    91       ///
    92       /// Write the content of the section.
    93       virtual void write(std::ostream& os) = 0;
    94     };
    95 
    96     /// \brief Constructor for LemonWriter.
    97     ///
    98     /// Constructor for LemonWriter which writes to the given stream.
    99     LemonWriter(std::ostream& _os) 
   100       : os(&_os), own_os(false) {}
   101 
   102     /// \brief Constructor for LemonWriter.
   103     ///
   104     /// Constructor for LemonWriter which writes to the given file.
   105     LemonWriter(const std::string& filename) 
   106       : os(0), own_os(true) {
   107       os = new std::ofstream(filename.c_str());
   108     }
   109 
   110     /// \brief Desctructor for LemonWriter.
   111     ///
   112     /// Desctructor for LemonWriter.
   113     ~LemonWriter() {
   114       if (own_os) {
   115 	delete os;
   116       }
   117     }
   118 
   119   private:
   120     LemonWriter(const LemonWriter&);
   121     void operator=(const LemonWriter&);
   122 
   123     void attach(SectionWriter& writer) {
   124       writers.push_back(&writer);
   125     }
   126 
   127   public:
   128 
   129     /// \brief Executes the LemonWriter.
   130     /// 
   131     /// It executes the LemonWriter.
   132     void run() {
   133       SectionWriters::iterator it;
   134       for (it = writers.begin(); it != writers.end(); ++it) {
   135 	*os << (*it)->header() << std::endl;
   136 	(*it)->write(*os);
   137       }
   138       *os << "@end" << std::endl;
   139     }
   140 
   141 
   142   private:
   143 
   144     std::ostream* os;
   145     bool own_os;
   146 
   147     typedef std::vector<SectionWriter*> SectionWriters;
   148     SectionWriters writers;
   149 
   150   };
   151 
   152   /// \brief Helper class for implementing the common SectionWriters.
   153   ///
   154   /// Helper class for implementing the common SectionWriters.
   155   class CommonSectionWriterBase : public LemonWriter::SectionWriter {
   156     typedef LemonWriter::SectionWriter Parent;
   157   protected:
   158     
   159     /// \brief Constructor for CommonSectionWriterBase.
   160     ///
   161     /// Constructor for CommonSectionWriterBase. It attach this writer to
   162     /// the given LemonWriter.
   163     CommonSectionWriterBase(LemonWriter& _writer) 
   164       : Parent(_writer) {}
   165 
   166     // Writers
   167 
   168     template <typename _Item>    
   169     class WriterBase {
   170     public:
   171       typedef _Item Item;
   172 
   173       virtual ~WriterBase() {}
   174 
   175       virtual void write(std::ostream& os, const Item& item) = 0;
   176     };
   177 
   178 
   179     template <typename _Item, typename _Map, typename _Writer>
   180     class MapWriter : public WriterBase<_Item> {
   181     public:
   182       typedef _Map Map;
   183       typedef _Writer Writer;
   184       typedef typename Writer::Value Value;
   185       typedef _Item Item;
   186       
   187       const Map& map;
   188       Writer writer;
   189 
   190       MapWriter(const Map& _map, const Writer& _writer) 
   191 	: map(_map), writer(_writer) {}
   192 
   193       virtual ~MapWriter() {}
   194 
   195       virtual void write(std::ostream& os, const Item& item) {
   196 	Value value = map[item];
   197 	writer.write(os, value);
   198       }
   199 
   200     };
   201 
   202 
   203     class ValueWriterBase {
   204     public:
   205       virtual void write(std::ostream&) = 0;
   206     };
   207 
   208     template <typename _Value, typename _Writer>
   209     class ValueWriter : public ValueWriterBase {
   210     public:
   211       typedef _Value Value;
   212       typedef _Writer Writer;
   213 
   214       ValueWriter(const Value& _value, const Writer& _writer)
   215  	: value(_value), writer(_writer) {}
   216 
   217       virtual void write(std::ostream& os) {
   218 	writer.write(os, value);
   219       }
   220     private:
   221       const Value& value;
   222       Writer writer;
   223     };
   224     
   225 
   226     template <typename _Item>
   227     class IdWriterBase {
   228     public:
   229       typedef _Item Item;
   230       virtual void write(std::ostream&, const Item&) const = 0;
   231     };
   232 
   233     template <typename _Item, typename _BoxedIdWriter>
   234     class IdWriter : public IdWriterBase<_Item> {
   235     public:
   236       typedef _Item Item;
   237       typedef _BoxedIdWriter BoxedIdWriter;
   238 
   239       const BoxedIdWriter& idWriter;
   240 
   241       IdWriter(const BoxedIdWriter& _idWriter) 
   242 	: idWriter(_idWriter) {}
   243 
   244       virtual void write(std::ostream& os, const Item& item) const {
   245 	return idWriter.writeId(os, item);
   246       }
   247     };
   248   };
   249 
   250   /// \ingroup io_group
   251   /// \brief SectionWriter for writing a graph's nodeset.
   252   ///
   253   /// The lemon format can store multiple graph nodesets with several maps.
   254   /// The nodeset section's header line is \c \@nodeset \c nodeset_id, but the
   255   /// \c nodeset_id may be empty.
   256   ///
   257   /// The first line of the section contains the names of the maps separated
   258   /// with white spaces. Each next lines describes a node in the nodeset, and
   259   /// contains the mapped values for each map.
   260   ///
   261   /// If the nodeset contains an \c "id" named map then it will be regarded
   262   /// as id map. This map should contain only unique values and when the 
   263   /// \c writeId() member will be called with a node it will write it's id.
   264   /// Otherwise if the \c _forceIdMap constructor parameter is true then
   265   /// the id map will be the id in the graph.
   266   ///
   267   /// \relates LemonWriter
   268   template <typename _Graph, typename _Traits = DefaultWriterTraits>
   269   class NodeSetWriter : public CommonSectionWriterBase {
   270     typedef CommonSectionWriterBase Parent;
   271   public:
   272 
   273     typedef _Graph Graph;
   274     typedef _Traits Traits;
   275     typedef typename Graph::Node Item;
   276 
   277     /// \brief Constructor.
   278     ///
   279     /// Constructor for NodeSetWriter. It creates the NodeSetWriter and
   280     /// attach it into the given LemonWriter. If the \c _forceIdMap
   281     /// parameter is true then the writer will write own id map when
   282     /// the user does not give "id" named map.
   283     NodeSetWriter(LemonWriter& _writer, const Graph& _graph, 
   284 		  const std::string& _id = std::string(), 
   285 		  bool _forceIdMap = true) 
   286       : Parent(_writer), idMap(0), forceIdMap(_forceIdMap), 
   287 	graph(_graph), id(_id) {}
   288 
   289     /// \brief Destructor.
   290     ///
   291     /// Destructor for NodeSetWriter.
   292     virtual ~NodeSetWriter() {
   293       typename MapWriters::iterator it;
   294       for (it = writers.begin(); it != writers.end(); ++it) {
   295 	delete it->second;
   296       }
   297     }
   298 
   299   private:
   300     NodeSetWriter(const NodeSetWriter&);
   301     void operator=(const NodeSetWriter&);
   302   
   303   public:
   304 
   305     /// \brief Add a new node map writer command for the writer.
   306     ///
   307     /// Add a new node map writer command for the writer.
   308     template <typename Map>
   309     NodeSetWriter& writeMap(std::string name, const Map& map) {
   310       return writeMap<typename Traits::
   311 	template Writer<typename Map::Value>, Map>(name, map);
   312     }
   313 
   314     /// \brief Add a new node map writer command for the writer.
   315     ///
   316     /// Add a new node map writer command for the writer.
   317     template <typename Writer, typename Map>
   318     NodeSetWriter& writeMap(std::string name, const Map& map, 
   319 			     const Writer& writer = Writer()) {
   320       writers.push_back(
   321 	make_pair(name, new MapWriter<Item, Map, Writer>(map, writer)));
   322       return *this;
   323     }
   324 
   325   protected:
   326 
   327     /// \brief The header of the section.
   328     ///
   329     /// It gives back the header of the section.
   330     virtual std::string header() {
   331       return "@nodeset " + id;
   332     }
   333 
   334     /// \brief  Writer function of the section.
   335     ///
   336     /// Write the content of the section.
   337     virtual void write(std::ostream& os) {
   338       for (int i = 0; i < (int)writers.size(); ++i) {
   339 	if (writers[i].first == "id") {
   340 	  idMap = writers[i].second;
   341 	  forceIdMap = false;
   342 	  break;
   343 	}
   344       }
   345       if (forceIdMap) {
   346 	os << "id\t";
   347       }
   348       for (int i = 0; i < (int)writers.size(); ++i) {
   349 	os << writers[i].first << '\t';
   350       }
   351       os << std::endl;
   352       for (typename Graph::NodeIt it(graph); it != INVALID; ++it) {
   353 	if (forceIdMap) {
   354 	  os << graph.id(it) << '\t';
   355 	}
   356 	for (int i = 0; i < (int)writers.size(); ++i) {
   357 	  writers[i].second->write(os, it);
   358 	  os << '\t';
   359 	}
   360 	os << std::endl;
   361       }
   362     }
   363 
   364   public:
   365 
   366     /// \brief Returns true if the nodeset can write the ids of the nodes.
   367     ///
   368     /// Returns true if the nodeset can write the ids of the nodes.
   369     /// It is possible only if an "id" named map was written or the 
   370     /// \c _forceIdMap constructor parameter was true.
   371     bool isIdWriter() const {
   372       return idMap != 0 || forceIdMap;
   373     }
   374 
   375     /// \brief Write the id of the given node.
   376     ///
   377     /// It writes the id of the given node. If there was written an "id"
   378     /// named map then it will write the map value belongs to the node.
   379     /// Otherwise if the \c forceId parameter was true it will write
   380     /// its id in the graph. 
   381     void writeId(std::ostream& os, const Item& item) const {
   382       if (forceIdMap) {
   383 	os << graph.id(item);
   384       } else {
   385 	idMap->write(os, item);
   386       }
   387     }
   388 
   389   private:
   390 
   391     typedef std::vector<std::pair<std::string, WriterBase<Item>*> > MapWriters;
   392     MapWriters writers;
   393 
   394     WriterBase<Item>* idMap;
   395     bool forceIdMap;
   396    
   397     const Graph& graph;   
   398     std::string id;
   399 
   400   };
   401 
   402   /// \ingroup io_group
   403   /// \brief SectionWriter for writing a graph's edgeset.
   404   ///
   405   /// The lemon format can store multiple graph edgesets with several maps.
   406   /// The edgeset section's header line is \c \@edgeset \c edgeset_id, but the
   407   /// \c edgeset_id may be empty.
   408   ///
   409   /// The first line of the section contains the names of the maps separated
   410   /// with white spaces. Each next lines describes a edge in the edgeset. The
   411   /// line contains the source and the target nodes' id and the mapped 
   412   /// values for each map.
   413   ///
   414   /// If the edgeset contains an \c "id" named map then it will be regarded
   415   /// as id map. This map should contain only unique values and when the 
   416   /// \c writeId() member will be called with a edge it will write it's id.
   417   /// Otherwise if the \c _forceIdMap constructor parameter is true then
   418   /// the id map will be the id in the graph.
   419   ///
   420   /// The edgeset writer needs a node id writer to identify which nodes
   421   /// have to be connected. If a NodeSetWriter can write the nodes' id,
   422   /// it will be able to use with this class.
   423   ///
   424   /// \relates LemonWriter
   425   template <typename _Graph, typename _Traits = DefaultWriterTraits>
   426   class EdgeSetWriter : public CommonSectionWriterBase {
   427     typedef CommonSectionWriterBase Parent;
   428   public:
   429 
   430     typedef _Graph Graph;
   431     typedef _Traits Traits;
   432     typedef typename Graph::Edge Item;
   433 
   434     /// \brief Constructor.
   435     ///
   436     /// Constructor for EdgeSetWriter. It creates the EdgeSetWriter and
   437     /// attach it into the given LemonWriter. It will write node ids by
   438     /// the \c _nodeIdWriter. If the \c _forceIdMap parameter is true 
   439     /// then the writer will write own id map when the user does not give 
   440     /// "id" named map.
   441     template <typename NodeIdWriter>
   442     EdgeSetWriter(LemonWriter& _writer, const Graph& _graph, 
   443 		  const NodeIdWriter& _nodeIdWriter, 
   444 		  const std::string& _id = std::string(),
   445 		  bool _forceIdMap = true)
   446       : Parent(_writer), idMap(0), forceIdMap(_forceIdMap),
   447 	graph(_graph), id(_id),
   448 	nodeIdWriter(new IdWriter<typename Graph::Node, NodeIdWriter>
   449 		     (_nodeIdWriter)) {} 
   450 
   451     /// \brief Destructor.
   452     ///
   453     /// Destructor for EdgeSetWriter.
   454     virtual ~EdgeSetWriter() {
   455       typename MapWriters::iterator it;
   456       for (it = writers.begin(); it != writers.end(); ++it) {
   457 	delete it->second;
   458       }
   459     }
   460 
   461   private:
   462     EdgeSetWriter(const EdgeSetWriter&);
   463     void operator=(const EdgeSetWriter&);
   464 
   465   public:
   466 
   467     /// \brief Add a new node map writer command for the writer.
   468     ///
   469     /// Add a new node map writer command for the writer.
   470     template <typename Map>
   471     EdgeSetWriter& writeMap(std::string name, const Map& map) {
   472       return writeMap<typename Traits::
   473 	template Writer<typename Map::Value>, Map>(name, map);
   474     }
   475 
   476     /// \brief Add a new node map writer command for the writer.
   477     ///
   478     /// Add a new node map writer command for the writer.
   479     template <typename Writer, typename Map>
   480     EdgeSetWriter& writeMap(std::string name, const Map& map, 
   481 			     const Writer& writer = Writer()) {
   482       writers.push_back(
   483 	make_pair(name, new MapWriter<Item, Map, Writer>(map, writer)));
   484       return *this;
   485     }
   486 
   487   protected:
   488 
   489     /// \brief The header of the section.
   490     ///
   491     /// It gives back the header of the section.
   492     virtual std::string header() {
   493       return "@edgeset " + id;
   494     }
   495 
   496     /// \brief  Writer function of the section.
   497     ///
   498     /// Write the content of the section.
   499     virtual void write(std::ostream& os) {
   500       for (int i = 0; i < (int)writers.size(); ++i) {
   501 	if (writers[i].first == "id") {
   502 	  idMap = writers[i].second;
   503 	  forceIdMap = false;
   504 	  break;
   505 	}
   506       }
   507       os << "\t\t";
   508       if (forceIdMap) {
   509 	os << "id\t";
   510       }
   511       for (int i = 0; i < (int)writers.size(); ++i) {
   512 	os << writers[i].first << '\t';
   513       }
   514       os << std::endl;
   515       for (typename Graph::EdgeIt it(graph); it != INVALID; ++it) {
   516 	nodeIdWriter->write(os, graph.source(it));
   517 	os << '\t';
   518 	nodeIdWriter->write(os, graph.target(it));
   519 	os << '\t';
   520 	if (forceIdMap) {
   521 	  os << graph.id(it) << '\t';
   522 	}
   523 	for (int i = 0; i < (int)writers.size(); ++i) {
   524 	  writers[i].second->write(os, it);
   525 	  os << '\t';
   526 	}
   527 	os << std::endl;
   528       }
   529     }
   530 
   531   public:
   532 
   533     /// \brief Returns true if the edgeset can write the ids of the edges.
   534     ///
   535     /// Returns true if the edgeset can write the ids of the edges.
   536     /// It is possible only if an "id" named map was written or the 
   537     /// \c _forceIdMap constructor parameter was true.
   538     bool isIdWriter() const {
   539       return forceIdMap || idMap != 0;
   540     }
   541 
   542     /// \brief Write the id of the given edge.
   543     ///
   544     /// It writes the id of the given edge. If there was written an "id"
   545     /// named map then it will write the map value belongs to the edge.
   546     /// Otherwise if the \c forceId parameter was true it will write
   547     /// its id in the graph. 
   548     void writeId(std::ostream& os, const Item& item) const {
   549       if (forceIdMap) {
   550 	os << graph.id(item);
   551       } else {
   552 	idMap->write(os, item);
   553       }
   554     } 
   555 
   556   private:
   557 
   558     typedef std::vector<std::pair<std::string, WriterBase<Item>*> > MapWriters;
   559     MapWriters writers;
   560 
   561     WriterBase<Item>* idMap;
   562     bool forceIdMap;
   563    
   564     const Graph& graph;   
   565     std::string id;
   566 
   567     std::auto_ptr<IdWriterBase<typename Graph::Node> > nodeIdWriter;
   568   };
   569 
   570   /// \ingroup io_group
   571   /// \brief SectionWriter for writing labeled nodes.
   572   ///
   573   /// The nodes section's header line is \c \@nodes \c nodes_id, but the
   574   /// \c nodes_id may be empty.
   575   ///
   576   /// Each line in the section contains the label of the node and 
   577   /// then the node id. 
   578   ///
   579   /// \relates LemonWriter
   580   template <typename _Graph>
   581   class NodeWriter : public CommonSectionWriterBase {
   582     typedef CommonSectionWriterBase Parent;
   583     typedef _Graph Graph;
   584     typedef typename Graph::Node Item;
   585   public:
   586     
   587     /// \brief Constructor.
   588     ///
   589     /// Constructor for NodeWriter. It creates the NodeWriter and
   590     /// attach it into the given LemonWriter. The given \c _IdWriter
   591     /// will write the nodes' id what can be a nodeset writer.
   592     template <typename _IdWriter>
   593     NodeWriter(LemonWriter& _writer, const _IdWriter& _idWriter, 
   594 	       const std::string& _id = std::string()) 
   595       : Parent(_writer), id(_id), 
   596 	idWriter(new IdWriter<typename Graph::Node, _IdWriter>(_idWriter)) {} 
   597 
   598     /// \brief Destructor.
   599     ///
   600     /// Destructor for NodeWriter.
   601     virtual ~NodeWriter() {}
   602 
   603   private:
   604     NodeWriter(const NodeWriter&);
   605     void operator=(const NodeWriter&);
   606 
   607   public:
   608 
   609     /// \brief Add a node writer command for the NodeWriter.
   610     ///
   611     /// Add a node writer command for the NodeWriter.
   612     void writeNode(const std::string& name, const Item& item) {
   613       writers.push_back(make_pair(name, &item));
   614     }
   615 
   616   protected:
   617 
   618     /// \brief Header checking function.
   619     ///
   620     /// It gives back true when the header line start with \c @nodes,
   621     /// and the header line's id and the writer's id are the same.
   622     virtual std::string header() {
   623       return "@nodes " + id;
   624     }
   625 
   626     /// \brief  Writer function of the section.
   627     ///
   628     /// Write the content of the section.
   629     virtual void write(std::ostream& os) {
   630       for (int i = 0; i < (int)writers.size(); ++i) {
   631 	os << writers[i].first << ' ';
   632 	idWriter->write(os, *(writers[i].second));
   633 	os << std::endl;
   634       }
   635     }
   636     
   637   private:
   638 
   639     std::string id;
   640 
   641     typedef std::vector<std::pair<std::string, const Item*> > ItemWriters;
   642     ItemWriters writers;
   643     std::auto_ptr<IdWriterBase<Item> > idWriter;
   644   };
   645 
   646   /// \ingroup io_group
   647   /// \brief SectionWriter for writeing labeled edges.
   648   ///
   649   /// The edges section's header line is \c \@edges \c edges_id, but the
   650   /// \c edges_id may be empty.
   651   ///
   652   /// Each line in the section contains the label of the edge and 
   653   /// then the edge id. 
   654   ///
   655   /// \relates LemonWriter
   656   template <typename _Graph>
   657   class EdgeWriter : public CommonSectionWriterBase {
   658     typedef CommonSectionWriterBase Parent;
   659     typedef _Graph Graph;
   660     typedef typename Graph::Edge Item;
   661   public:
   662     
   663     /// \brief Constructor.
   664     ///
   665     /// Constructor for EdgeWriter. It creates the EdgeWriter and
   666     /// attach it into the given LemonWriter. The given \c _IdWriter
   667     /// will write the edges' id what can be a edgeset writer.
   668     template <typename _IdWriter>
   669     EdgeWriter(LemonWriter& _writer, const _IdWriter& _idWriter, 
   670 	       const std::string& _id = std::string()) 
   671       : Parent(_writer), id(_id), 
   672 	idWriter(new IdWriter<typename Graph::Edge, _IdWriter>(_idWriter)) {} 
   673 
   674     /// \brief Destructor.
   675     ///
   676     /// Destructor for EdgeWriter.
   677     virtual ~EdgeWriter() {}
   678   private:
   679     EdgeWriter(const EdgeWriter&);
   680     void operator=(const EdgeWriter&);
   681 
   682   public:
   683 
   684     /// \brief Add an edge writer command for the NodeWriter.
   685     ///
   686     /// Add an edge writer command for the NodeWriter.
   687     void writeEdge(const std::string& name, const Item& item) {
   688       writers.push_back(make_pair(name, &item));
   689     }
   690 
   691   protected:
   692 
   693     /// \brief Header checking function.
   694     ///
   695     /// It gives back true when the header line start with \c @nodes,
   696     /// and the header line's id and the writer's id are the same.
   697     virtual std::string header() {
   698       return "@edges " + id;
   699     }
   700 
   701     /// \brief  Writer function of the section.
   702     ///
   703     /// Write the content of the section.
   704     virtual void write(std::ostream& os) {
   705       for (int i = 0; i < (int)writers.size(); ++i) {
   706 	os << writers[i].first << ' ';
   707 	idWriter->write(os, *(writers[i].second));
   708 	os << std::endl;
   709       }
   710     }
   711     
   712   private:
   713 
   714     std::string id;
   715 
   716     typedef std::vector<std::pair<std::string, const Item*> > ItemWriters;
   717     ItemWriters writers;
   718 
   719     std::auto_ptr<IdWriterBase<Item> > idWriter;
   720   };
   721 
   722   /// \ingroup io_group
   723   /// \brief SectionWriter for attributes.
   724   ///
   725   /// The lemon format can store multiple attribute set. Each set has
   726   /// the header line \c \@attributes \c attributeset_id, but the 
   727   /// attributeset_id may be empty.
   728   ///
   729   /// The attributeset section contains several lines. Each of them starts
   730   /// with the name of attribute and then the value.
   731   ///
   732   /// \relates LemonWriter
   733   template <typename _Traits = DefaultWriterTraits>
   734   class AttributeWriter : public CommonSectionWriterBase {
   735     typedef CommonSectionWriterBase Parent;
   736     typedef _Traits Traits; 
   737   public:
   738     /// \brief Constructor.
   739     ///
   740     /// Constructor for AttributeWriter. It creates the AttributeWriter and
   741     /// attach it into the given LemonWriter.
   742     AttributeWriter(LemonWriter& _writer, 
   743 		    const std::string& _id = std::string()) 
   744       : Parent(_writer), id(_id) {}
   745 
   746     /// \brief Destructor.
   747     ///
   748     /// Destructor for AttributeWriter.
   749     virtual ~AttributeWriter() {
   750       typename Writers::iterator it;
   751       for (it = writers.begin(); it != writers.end(); ++it) {
   752 	delete it->second;
   753       }
   754     }
   755 
   756   private:
   757     AttributeWriter(const AttributeWriter&);
   758     void operator=(AttributeWriter&);
   759 
   760   public:
   761     /// \brief Add an attribute writer command for the writer.
   762     ///
   763     /// Add an attribute writer command for the writer.
   764     template <typename Value>
   765     AttributeWriter& writeAttribute(const std::string& id, 
   766 				    const Value& value) {
   767       return 
   768 	writeAttribute<typename Traits::template Writer<Value> >(id, value);
   769     }
   770 
   771     /// \brief Add an attribute writer command for the writer.
   772     ///
   773     /// Add an attribute writer command for the writer.
   774     template <typename Writer, typename Value>
   775     AttributeWriter& writeAttribute(const std::string& name, 
   776 				    const Value& value,
   777 				    const Writer& writer = Writer()) {
   778       writers.push_back(make_pair(name, new ValueWriter<Value, Writer>
   779       			       (value, writer)));
   780       return *this;
   781     }
   782 
   783   protected:
   784 
   785     /// \brief The header of section.
   786     ///
   787     /// It gives back the header of the section.
   788     std::string header() {
   789       return "@attributes " + id;
   790     }
   791 
   792     /// \brief  Writer function of the section.
   793     ///
   794     /// Write the content of the section.
   795     void write(std::ostream& os) {
   796       typename Writers::iterator it;
   797       for (it = writers.begin(); it != writers.end(); ++it) {
   798 	os << it->first << ' ';
   799 	it->second->write(os);
   800 	os << std::endl;
   801       }
   802     }    
   803 
   804   private:
   805     std::string id;
   806 
   807     typedef std::vector<std::pair<std::string, ValueWriterBase*> > Writers;
   808     Writers writers;  
   809   };
   810 
   811 
   812 }
   813 #endif