COIN-OR::LEMON - Graph Library

source: lemon-0.x/src/lemon/lemon_writer.h @ 1410:dcfad73b3965

Last change on this file since 1410:dcfad73b3965 was 1409:d2d1f8fa187b, checked in by Balazs Dezso, 19 years ago

LemonWriter? and GraphWriter?.
Little bit better documentation.

File size: 23.4 KB
Line 
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
37namespace 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(is, 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
Note: See TracBrowser for help on using the repository browser.