COIN-OR::LEMON - Graph Library

source: lemon-0.x/lemon/lemon_writer.h @ 2091:c8ccc1f8fd51

Last change on this file since 2091:c8ccc1f8fd51 was 2084:59769591eb60, checked in by Balazs Dezso, 18 years ago

Documentation improvements

Rearrangements:

IO modules
Algorithms

New documentation:

SwapBpUGraphAdaptor

Demos:

strongly_connected_orientation.cc

Benchmarks:

swap_bipartite_bench.cc

File size: 40.2 KB
RevLine 
[1409]1/* -*- C++ -*-
2 *
[1956]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
[1409]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
[2084]19///\ingroup lemon_io
[1409]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>
[1993]35#include <lemon/bits/invalid.h>
[1421]36#include <lemon/graph_utils.h>
[1409]37#include <lemon/bits/item_writer.h>
[1993]38#include <lemon/bits/utility.h>
[1421]39#include <lemon/maps.h>
[1705]40#include <lemon/xy.h>
[1409]41
[1476]42#include <lemon/concept_check.h>
43#include <lemon/concept/maps.h>
44
[1409]45
46namespace lemon {
47
[1476]48  namespace _writer_bits {
49   
50    template <typename Item>
[1901]51    class ItemLabelWriter {
[1476]52    public:
53
[1901]54      bool isLabelWriter() { return true; }
[1476]55
[1901]56      void writeLabel(std::ostream&, const Item&) {}
[1476]57     
[1901]58      template <class _ItemLabelWriter>
[1476]59      struct Constraints {
60        void constraints() {
[1901]61          bool b = writer.isLabelWriter();
[1476]62          ignore_unused_variable_warning(b);
[1901]63          writer.writeLabel(os, item);
[1476]64        }
[1901]65        _ItemLabelWriter& writer;
[1476]66        std::ostream& os;
[1492]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;
[1476]86      };
87
88    };
89
[1705]90    template <typename Map>
91    struct Ref { typedef const Map& Type; };
92
93    template <typename Graph, typename Map>
94    class ForwardComposeMap {
95    public:
[1909]96      typedef typename Graph::UEdge Key;
[1705]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:
[1909]120      typedef typename Graph::UEdge Key;
[1705]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
[1845]169
170    template <typename _Item>   
171    class MapWriterBase {
172    public:
173      typedef _Item Item;
174
175      virtual ~MapWriterBase() {}
176
[1852]177      virtual void write(std::ostream& os, const Item& item) const = 0;
[1845]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
[1852]197      virtual void write(std::ostream& os, const Item& item) const {
[1845]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>
[1901]230    class LabelWriterBase {
[1845]231    public:
232      typedef _Item Item;
[1901]233      virtual ~LabelWriterBase() {}
[1845]234      virtual void write(std::ostream&, const Item&) const = 0;
[1901]235      virtual bool isLabelWriter() const = 0;
[1845]236    };
237
[1901]238    template <typename _Item, typename _BoxedLabelWriter>
239    class LabelWriter : public LabelWriterBase<_Item> {
[1845]240    public:
241      typedef _Item Item;
[1901]242      typedef _BoxedLabelWriter BoxedLabelWriter;
[1845]243
[1901]244      const BoxedLabelWriter& labelWriter;
[1845]245
[1901]246      LabelWriter(const BoxedLabelWriter& _labelWriter)
247        : labelWriter(_labelWriter) {}
[1845]248
249      virtual void write(std::ostream& os, const Item& item) const {
[1901]250        labelWriter.writeLabel(os, item);
[1845]251      }
252
[1901]253      virtual bool isLabelWriter() const {
254        return labelWriter.isLabelWriter();
[1845]255      }
256    };
257
[1476]258  }
259
[2084]260  /// \ingroup lemon_io
[1409]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      }
[1494]305     
306      virtual ~SectionWriter() {}
[1409]307
308      /// \brief The header of section.
309      ///
310      /// It gives back the header of the section.
311      virtual std::string header() = 0;
312
[2084]313      /// \brief Writer function of the section.
[1409]314      ///
315      /// Write the content of the section.
316      virtual void write(std::ostream& os) = 0;
[2084]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; }
[1409]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) {
[2084]363        if ((*it)->valid()) {
364          *os << (*it)->header() << std::endl;
365          (*it)->write(*os);
366        }
[1409]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
[2016]382  /// \ingroup section_io
[1409]383  /// \brief SectionWriter for writing a graph's nodeset.
384  ///
385  /// The lemon format can store multiple graph nodesets with several maps.
[1901]386  /// The nodeset section's header line is \c \@nodeset \c nodeset_name, but
387  /// the \c nodeset_name may be empty.
[1409]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  ///
[1901]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.
[1409]398  ///
399  /// \relates LemonWriter
400  template <typename _Graph, typename _Traits = DefaultWriterTraits>
[1845]401  class NodeSetWriter : public LemonWriter::SectionWriter {
402    typedef LemonWriter::SectionWriter Parent;
[1409]403  public:
404
405    typedef _Graph Graph;
406    typedef _Traits Traits;
[1429]407    typedef typename Graph::Node Node;
[1409]408
409    /// \brief Constructor.
410    ///
411    /// Constructor for NodeSetWriter. It creates the NodeSetWriter and
[1901]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.
[1409]415    NodeSetWriter(LemonWriter& _writer, const Graph& _graph,
[1901]416                  const std::string& _name = std::string(),
417                  bool _forceLabelMap = true)
418      : Parent(_writer), labelMap(0), forceLabelMap(_forceLabelMap),
419        graph(_graph), name(_name) {}
[1409]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>
[1421]441    NodeSetWriter& writeNodeMap(std::string name, const Map& map) {
442      return writeNodeMap<typename Traits::
[1409]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>
[1421]450    NodeSetWriter& writeNodeMap(std::string name, const Map& map,
451                            const Writer& writer = Writer()) {
[1492]452      checkConcept<concept::ReadMap<Node, typename Map::Value>, Map>();
453      checkConcept<_writer_bits::ItemWriter<typename Map::Value>, Writer>();
[1409]454      writers.push_back(
[1845]455        make_pair(name, new _writer_bits::
456                  MapWriter<Node, Map, Writer>(map, writer)));
[1409]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() {
[1901]466      return "@nodeset " + name;
[1409]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) {
[2084]474        if (writers[i].first == "label") {
[1901]475          labelMap = writers[i].second;
476          forceLabelMap = false;
[1409]477          break;
478        }
479      }
[1901]480      if (forceLabelMap) {
481        os << "label\t";
[1409]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) {
[1901]488        if (forceLabelMap) {
[1409]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
[1901]501    /// \brief Returns true if the nodeset can write the labels of the nodes.
[1409]502    ///
[1901]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;
[1409]508    }
509
[1901]510    /// \brief Write the label of the given node.
[1409]511    ///
[1901]512    /// It writes the label of the given node. If there was written an "label"
[1409]513    /// named map then it will write the map value belongs to the node.
[1901]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) {
[1409]518        os << graph.id(item);
519      } else {
[1901]520        labelMap->write(os, item);
[1409]521      }
522    }
523
524  private:
525
[1845]526    typedef std::vector<std::pair<std::string, _writer_bits::
527                                  MapWriterBase<Node>*> > MapWriters;
[1409]528    MapWriters writers;
529
[1901]530    _writer_bits::MapWriterBase<Node>* labelMap;
531    bool forceLabelMap;
[1409]532   
[1705]533    const Graph& graph;   
[1901]534    std::string name;
[1409]535
536  };
537
[2016]538  /// \ingroup section_io
[1421]539  /// \brief SectionWriter for writing a graph's edgesets.
[1409]540  ///
[1421]541  /// The lemon format can store multiple graph edgesets with several maps.
[1901]542  /// The edgeset section's header line is \c \@edgeset \c edgeset_name, but
543  /// the \c edgeset_name may be empty.
[1409]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
[1901]547  /// line contains the source and the target nodes' label and the mapped
[1409]548  /// values for each map.
549  ///
[1901]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.
[1409]555  ///
[1901]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,
[1409]558  /// it will be able to use with this class.
559  ///
560  /// \relates LemonWriter
561  template <typename _Graph, typename _Traits = DefaultWriterTraits>
[1845]562  class EdgeSetWriter : public LemonWriter::SectionWriter {
563    typedef LemonWriter::SectionWriter Parent;
[1409]564  public:
565
566    typedef _Graph Graph;
567    typedef _Traits Traits;
[1429]568    typedef typename Graph::Node Node;
569    typedef typename Graph::Edge Edge;
[1409]570
571    /// \brief Constructor.
572    ///
573    /// Constructor for EdgeSetWriter. It creates the EdgeSetWriter and
[1901]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>
[1409]579    EdgeSetWriter(LemonWriter& _writer, const Graph& _graph,
[1901]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));
[1476]588    }
[1409]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
[1421]606    /// \brief Add a new edge map writer command for the writer.
[1409]607    ///
[1421]608    /// Add a new edge map writer command for the writer.
[1409]609    template <typename Map>
[1421]610    EdgeSetWriter& writeEdgeMap(std::string name, const Map& map) {
611      return writeEdgeMap<typename Traits::
[1409]612        template Writer<typename Map::Value>, Map>(name, map);
613    }
614
[1421]615    /// \brief Add a new edge map writer command for the writer.
[1409]616    ///
[1421]617    /// Add a new edge map writer command for the writer.
[1409]618    template <typename Writer, typename Map>
[1421]619    EdgeSetWriter& writeEdgeMap(std::string name, const Map& map,
620                            const Writer& writer = Writer()) {
[1492]621      checkConcept<concept::ReadMap<Edge, typename Map::Value>, Map>();
622      checkConcept<_writer_bits::ItemWriter<typename Map::Value>, Writer>();
[1409]623      writers.push_back(
[1845]624        make_pair(name, new _writer_bits::
625                  MapWriter<Edge, Map, Writer>(map, writer)));
[1409]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() {
[1901]635      return "@edgeset " + name;
[1409]636    }
637
638    /// \brief  Writer function of the section.
639    ///
640    /// Write the content of the section.
641    virtual void write(std::ostream& os) {
[1901]642      if (!nodeLabelWriter->isLabelWriter()) {
643        throw DataFormatError("Cannot find nodeset or label map");
[1476]644      }
[1409]645      for (int i = 0; i < (int)writers.size(); ++i) {
[2084]646        if (writers[i].first == "label") {
[1901]647          labelMap = writers[i].second;
648          forceLabelMap = false;
[1409]649          break;
650        }
651      }
652      os << "\t\t";
[1901]653      if (forceLabelMap) {
654        os << "label\t";
[1409]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) {
[1901]661        nodeLabelWriter->write(os, graph.source(it));
[1409]662        os << '\t';
[1901]663        nodeLabelWriter->write(os, graph.target(it));
[1409]664        os << '\t';
[1901]665        if (forceLabelMap) {
[1409]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
[1901]678    /// \brief Returns true if the edgeset can write the labels of the edges.
[1409]679    ///
[1901]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;
[1409]685    }
686
[1901]687    /// \brief Write the label of the given edge.
[1409]688    ///
[1901]689    /// It writes the label of the given edge. If there was written an "label"
[1409]690    /// named map then it will write the map value belongs to the edge.
[1901]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) {
[1409]695        os << graph.id(item);
696      } else {
[1901]697        labelMap->write(os, item);
[1409]698      }
699    }
700
701  private:
702
[1845]703    typedef std::vector<std::pair<std::string, _writer_bits::
704                                  MapWriterBase<Edge>*> > MapWriters;
[1409]705    MapWriters writers;
706
[1901]707    _writer_bits::MapWriterBase<Edge>* labelMap;
708    bool forceLabelMap;
[1409]709   
[1705]710    const Graph& graph;   
[1901]711    std::string name;
[1421]712
[1901]713    std::auto_ptr<_writer_bits::LabelWriterBase<Node> > nodeLabelWriter;
[1421]714  };
715
[2016]716  /// \ingroup section_io
[1421]717  /// \brief SectionWriter for writing a undirected edgeset.
718  ///
719  /// The lemon format can store multiple undirected edgesets with several
[1909]720  /// maps. The undirected edgeset section's header line is \c \@uedgeset
721  /// \c uedgeset_name, but the \c uedgeset_name may be empty.
[1421]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
[1901]725  /// edgeset. The line contains the two connected nodes' label and the mapped
[1421]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  ///
[1901]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.
[1421]739  ///
[1901]740  /// The undirected edgeset writer needs a node label writer to identify
[1421]741  /// which nodes have to be connected. If a NodeSetWriter can write the
[1901]742  /// nodes' label, it will be able to use with this class.
[1421]743  ///
744  /// \relates LemonWriter
745  template <typename _Graph, typename _Traits = DefaultWriterTraits>
[1909]746  class UEdgeSetWriter : public LemonWriter::SectionWriter {
[1845]747    typedef LemonWriter::SectionWriter Parent;
[1421]748  public:
749
750    typedef _Graph Graph;
751    typedef _Traits Traits;
[1429]752    typedef typename Graph::Node Node;
753    typedef typename Graph::Edge Edge;
[1909]754    typedef typename Graph::UEdge UEdge;
[1421]755
756    /// \brief Constructor.
757    ///
[1909]758    /// Constructor for UEdgeSetWriter. It creates the UEdgeSetWriter
[1901]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>
[1909]764    UEdgeSetWriter(LemonWriter& _writer, const Graph& _graph,
[1901]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));
[1476]773    }
[1421]774
775    /// \brief Destructor.
776    ///
[1909]777    /// Destructor for UEdgeSetWriter.
778    virtual ~UEdgeSetWriter() {
[1421]779      typename MapWriters::iterator it;
780      for (it = writers.begin(); it != writers.end(); ++it) {
781        delete it->second;
782      }
783    }
784
785  private:
[1909]786    UEdgeSetWriter(const UEdgeSetWriter&);
787    void operator=(const UEdgeSetWriter&);
[1421]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>
[1909]795    UEdgeSetWriter& writeUEdgeMap(std::string name, const Map& map) {
796      return writeUEdgeMap<typename Traits::
[1421]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>
[1909]804    UEdgeSetWriter& writeUEdgeMap(std::string name, const Map& map,
[1421]805                                          const Writer& writer = Writer()) {
[1909]806      checkConcept<concept::ReadMap<UEdge, typename Map::Value>, Map>();
[1492]807      checkConcept<_writer_bits::ItemWriter<typename Map::Value>, Writer>();
[1421]808      writers.push_back(
[1845]809        make_pair(name, new _writer_bits::
[1909]810                  MapWriter<UEdge, Map, Writer>(map, writer)));
[1421]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>
[1909]818    UEdgeSetWriter& writeEdgeMap(std::string name, const Map& map) {
[1492]819      return writeEdgeMap<typename Traits::
820        template Writer<typename Map::Value>, Map>(name, map);
[1421]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>
[1909]827    UEdgeSetWriter& writeEdgeMap(std::string name, const Map& map,
[1421]828                                     const Writer& writer = Writer()) {
[1492]829      checkConcept<concept::ReadMap<Edge, typename Map::Value>, Map>();
830      checkConcept<_writer_bits::ItemWriter<typename Map::Value>, Writer>();
[1909]831      writeUEdge("+" + name,
[1705]832                     _writer_bits::forwardComposeMap(graph, map), writer);
[1909]833      writeUEdge("-" + name,
[1705]834                     _writer_bits::backwardComposeMap(graph, map), writer);
[1421]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() {
[1909]844      return "@uedgeset " + name;
[1421]845    }
846
847    /// \brief  Writer function of the section.
848    ///
849    /// Write the content of the section.
850    virtual void write(std::ostream& os) {
[1901]851      if (!nodeLabelWriter->isLabelWriter()) {
852        throw DataFormatError("Cannot find nodeset or label map");
[1476]853      }
[1421]854      for (int i = 0; i < (int)writers.size(); ++i) {
[1901]855        if (writers[i].first == "label") {
856          labelMap = writers[i].second;
857          forceLabelMap = false;
[1421]858          break;
859        }
860      }
861      os << "\t\t";
[1901]862      if (forceLabelMap) {
863        os << "label\t";
[1421]864      }
865      for (int i = 0; i < (int)writers.size(); ++i) {
866        os << writers[i].first << '\t';
867      }
868      os << std::endl;
[1909]869      for (typename Graph::UEdgeIt it(graph); it != INVALID; ++it) {
[1901]870        nodeLabelWriter->write(os, graph.source(it));
[1421]871        os << '\t';
[1901]872        nodeLabelWriter->write(os, graph.target(it));
[1421]873        os << '\t';
[1901]874        if (forceLabelMap) {
[1421]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
[1901]887    /// \brief Returns true if the undirected edgeset can write the labels of
[1421]888    /// the edges.
889    ///
[1901]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;
[1421]895    }
896
[1901]897    /// \brief Write the label of the given undirected edge.
[1421]898    ///
[1901]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
[1421]902    /// will write its id in the graph.
[1909]903    void writeLabel(std::ostream& os, const UEdge& item) const {
[1901]904      if (forceLabelMap) {
[1429]905        os << graph.id(item);
906      } else {
[1901]907        labelMap->write(os, item);
[1429]908      }
909    }
910
[1901]911    /// \brief Write the label of the given edge.
[1429]912    ///
[1901]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
[1429]916    /// will write its id in the graph. If the edge is forward map
917    /// then its prefix character is \c '+' elsewhere \c '-'.
[1901]918    void writeLabel(std::ostream& os, const Edge& item) const {
[1690]919      if (graph.direction(item)) {
[1429]920        os << "+ ";
921      } else {
922        os << "- ";
923      }
[1901]924      if (forceLabelMap) {
[1421]925        os << graph.id(item);
926      } else {
[1901]927        labelMap->write(os, item);
[1421]928      }
929    }
930
931  private:
932
[1845]933    typedef std::vector<std::pair<std::string, _writer_bits::
[1909]934                                  MapWriterBase<UEdge>*> > MapWriters;
[1421]935    MapWriters writers;
936
[1909]937    _writer_bits::MapWriterBase<UEdge>* labelMap;
[1901]938    bool forceLabelMap;
[1421]939   
[1705]940    const Graph& graph;   
[1901]941    std::string name;
[1409]942
[1901]943    std::auto_ptr<_writer_bits::LabelWriterBase<Node> > nodeLabelWriter;
[1409]944  };
945
[2016]946  /// \ingroup section_io
[1901]947  /// \brief SectionWriter for writing named nodes.
[1409]948  ///
[1901]949  /// The nodes section's header line is \c \@nodes \c nodes_name, but the
950  /// \c nodes_name may be empty.
[1409]951  ///
[1901]952  /// Each line in the section contains the name of the node and
953  /// then the node label.
[1409]954  ///
955  /// \relates LemonWriter
956  template <typename _Graph>
[1845]957  class NodeWriter : public LemonWriter::SectionWriter {
958    typedef LemonWriter::SectionWriter Parent;
[1409]959    typedef _Graph Graph;
[1429]960    typedef typename Graph::Node Node;
[1409]961  public:
962   
963    /// \brief Constructor.
964    ///
965    /// Constructor for NodeWriter. It creates the NodeWriter and
[1901]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));
[1476]975    }
976
[1409]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.
[1429]992    void writeNode(const std::string& name, const Node& item) {
[1409]993      writers.push_back(make_pair(name, &item));
994    }
995
996  protected:
997
[1901]998    /// \brief The header of the section.
[1409]999    ///
[1901]1000    /// It gives back the header of the section.
[1409]1001    virtual std::string header() {
[1901]1002      return "@nodes " + name;
[1409]1003    }
1004
1005    /// \brief  Writer function of the section.
1006    ///
1007    /// Write the content of the section.
1008    virtual void write(std::ostream& os) {
[1901]1009      if (!labelWriter->isLabelWriter()) {
1010        throw DataFormatError("Cannot find nodeset or label map");
[1476]1011      }
[1409]1012      for (int i = 0; i < (int)writers.size(); ++i) {
1013        os << writers[i].first << ' ';
[1901]1014        labelWriter->write(os, *(writers[i].second));
[1409]1015        os << std::endl;
1016      }
1017    }
[2084]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(); }
[1409]1023   
1024  private:
1025
[1901]1026    std::string name;
[1409]1027
[1429]1028    typedef std::vector<std::pair<std::string, const Node*> > NodeWriters;
1029    NodeWriters writers;
[1901]1030    std::auto_ptr<_writer_bits::LabelWriterBase<Node> > labelWriter;
[1409]1031  };
1032
[2016]1033  /// \ingroup section_io
[1901]1034  /// \brief SectionWriter for writing named edges.
[1409]1035  ///
[1901]1036  /// The edges section's header line is \c \@edges \c edges_name, but the
1037  /// \c edges_name may be empty.
[1409]1038  ///
[1901]1039  /// Each line in the section contains the name of the edge and
1040  /// then the edge label.
[1409]1041  ///
1042  /// \relates LemonWriter
1043  template <typename _Graph>
[1845]1044  class EdgeWriter : public LemonWriter::SectionWriter {
1045    typedef LemonWriter::SectionWriter Parent;
[1409]1046    typedef _Graph Graph;
[1429]1047    typedef typename Graph::Edge Edge;
[1409]1048  public:
1049   
1050    /// \brief Constructor.
1051    ///
1052    /// Constructor for EdgeWriter. It creates the EdgeWriter and
[1901]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));
[1476]1061    }
[1409]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
[1421]1073    /// \brief Add an edge writer command for the EdgeWriter.
[1409]1074    ///
[1421]1075    /// Add an edge writer command for the EdgeWriter.
[1429]1076    void writeEdge(const std::string& name, const Edge& item) {
[1409]1077      writers.push_back(make_pair(name, &item));
1078    }
1079
1080  protected:
1081
[1901]1082    /// \brief The header of the section.
[1409]1083    ///
[1901]1084    /// It gives back the header of the section.
[1421]1085    virtual std::string header() {
[1901]1086      return "@edges " + name;
[1421]1087    }
1088
1089    /// \brief  Writer function of the section.
1090    ///
1091    /// Write the content of the section.
1092    virtual void write(std::ostream& os) {
[1901]1093      if (!labelWriter->isLabelWriter()) {
1094        throw DataFormatError("Cannot find edgeset or label map");
[1476]1095      }
[1421]1096      for (int i = 0; i < (int)writers.size(); ++i) {
1097        os << writers[i].first << ' ';
[1901]1098        labelWriter->write(os, *(writers[i].second));
[1421]1099        os << std::endl;
1100      }
1101    }
[2084]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(); }
[1421]1107   
1108  private:
1109
[1901]1110    std::string name;
[1421]1111
[1429]1112    typedef std::vector<std::pair<std::string, const Edge*> > EdgeWriters;
1113    EdgeWriters writers;
[1421]1114
[1901]1115    std::auto_ptr<_writer_bits::LabelWriterBase<Edge> > labelWriter;
[1421]1116  };
1117
[2016]1118  /// \ingroup section_io
[1901]1119  /// \brief SectionWriter for writing named undirected edges.
[1421]1120  ///
[1909]1121  /// The undirected edges section's header line is \c \@uedges
1122  /// \c uedges_name, but the \c uedges_name may be empty.
[1421]1123  ///
[1901]1124  /// Each line in the section contains the name of the undirected edge and
1125  /// then the undirected edge label.
[1421]1126  ///
1127  /// \relates LemonWriter
1128  template <typename _Graph>
[1909]1129  class UEdgeWriter : public LemonWriter::SectionWriter {
[1845]1130    typedef LemonWriter::SectionWriter Parent;
[1421]1131    typedef _Graph Graph;
[1429]1132    typedef typename Graph::Node Node;
1133    typedef typename Graph::Edge Edge;
[1909]1134    typedef typename Graph::UEdge UEdge;
[1421]1135  public:
1136   
1137    /// \brief Constructor.
1138    ///
[1909]1139    /// Constructor for UEdgeWriter. It creates the UEdgeWriter and
[1901]1140    /// attach it into the given LemonWriter. The given \c _LabelWriter
1141    /// will write the undirected edges' label what can be an undirected
[1421]1142    /// edgeset writer.
[1901]1143    template <typename _LabelWriter>
[1909]1144    UEdgeWriter(LemonWriter& _writer, const _LabelWriter& _labelWriter,
[1901]1145               const std::string& _name = std::string())
1146      : Parent(_writer), name(_name) {
1147      checkConcept<_writer_bits::ItemLabelWriter<Edge>, _LabelWriter>();
[1909]1148      checkConcept<_writer_bits::ItemLabelWriter<UEdge>, _LabelWriter>();
1149      uEdgeLabelWriter.reset(new _writer_bits::
1150                              LabelWriter<UEdge, _LabelWriter>(_labelWriter));
[1901]1151      edgeLabelWriter.reset(new _writer_bits::
1152                         LabelWriter<Edge, _LabelWriter>(_labelWriter));
[1476]1153    }
[1421]1154
1155    /// \brief Destructor.
1156    ///
[1909]1157    /// Destructor for UEdgeWriter.
1158    virtual ~UEdgeWriter() {}
[1421]1159  private:
[1909]1160    UEdgeWriter(const UEdgeWriter&);
1161    void operator=(const UEdgeWriter&);
[1421]1162
1163  public:
1164
[1909]1165    /// \brief Add an edge writer command for the UEdgeWriter.
[1429]1166    ///
[1909]1167    /// Add an edge writer command for the UEdgeWriter.
[1429]1168    void writeEdge(const std::string& name, const Edge& item) {
1169      edgeWriters.push_back(make_pair(name, &item));
1170    }
1171
[1909]1172    /// \brief Add an undirected edge writer command for the UEdgeWriter.
[1421]1173    ///
[1909]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));
[1421]1177    }
1178
1179  protected:
1180
[1901]1181    /// \brief The header of the section.
[1421]1182    ///
[1901]1183    /// It gives back the header of the section.
[1409]1184    virtual std::string header() {
[1909]1185      return "@uedges " + name;
[1409]1186    }
1187
1188    /// \brief  Writer function of the section.
1189    ///
1190    /// Write the content of the section.
1191    virtual void write(std::ostream& os) {
[1901]1192      if (!edgeLabelWriter->isLabelWriter()) {
1193        throw DataFormatError("Cannot find undirected edgeset or label map");
[1476]1194      }
[1909]1195      if (!uEdgeLabelWriter->isLabelWriter()) {
[1901]1196        throw DataFormatError("Cannot find undirected edgeset or label map");
[1476]1197      }
[1909]1198      for (int i = 0; i < (int)uEdgeWriters.size(); ++i) {
1199        os << uEdgeWriters[i].first << ' ';
1200        uEdgeLabelWriter->write(os, *(uEdgeWriters[i].second));
[1429]1201        os << std::endl;
1202      }
1203      for (int i = 0; i < (int)edgeWriters.size(); ++i) {
1204        os << edgeWriters[i].first << ' ';
[1901]1205        edgeLabelWriter->write(os, *(edgeWriters[i].second));
[1409]1206        os << std::endl;
1207      }
1208    }
[2084]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    }
[1409]1216   
1217  private:
1218
[1901]1219    std::string name;
[1409]1220
[1429]1221    typedef std::vector<std::pair<std::string,
[1909]1222                                  const UEdge*> > UEdgeWriters;
1223    UEdgeWriters uEdgeWriters;
1224    std::auto_ptr<_writer_bits::LabelWriterBase<UEdge> > uEdgeLabelWriter;
[1409]1225
[1429]1226    typedef std::vector<std::pair<std::string, const Edge*> > EdgeWriters;
1227    EdgeWriters edgeWriters;
[1901]1228    std::auto_ptr<_writer_bits::LabelWriterBase<Edge> > edgeLabelWriter;
[1429]1229
[1409]1230  };
1231
[2016]1232  /// \ingroup section_io
[1409]1233  /// \brief SectionWriter for attributes.
1234  ///
1235  /// The lemon format can store multiple attribute set. Each set has
[1901]1236  /// the header line \c \@attributes \c attributes_name, but the
1237  /// attributeset_name may be empty.
[1409]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>
[1845]1244  class AttributeWriter : public LemonWriter::SectionWriter {
1245    typedef LemonWriter::SectionWriter Parent;
[1409]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,
[1901]1253                    const std::string& _name = std::string())
1254      : Parent(_writer), name(_name) {}
[1409]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>
[1901]1275    AttributeWriter& writeAttribute(const std::string& name,
[1409]1276                                    const Value& value) {
1277      return
[1901]1278        writeAttribute<typename Traits::template Writer<Value> >(name, value);
[1409]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()) {
[1492]1288      checkConcept<_writer_bits::ItemWriter<Value>, Writer>();
[1845]1289      writers.push_back(make_pair(name, new _writer_bits::
1290                                  ValueWriter<Value, Writer>(value, writer)));
[1409]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() {
[1901]1300      return "@attributes " + name;
[1409]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
[2084]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
[1409]1320  private:
[1901]1321    std::string name;
[1409]1322
[1845]1323    typedef std::vector<std::pair<std::string,
1324                                  _writer_bits::ValueWriterBase*> > Writers;
[1409]1325    Writers writers; 
1326  };
1327
1328
1329}
1330#endif
Note: See TracBrowser for help on using the repository browser.