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