COIN-OR::LEMON - Graph Library

source: lemon-0.x/src/lemon/lemon_reader.h @ 1421:7a21e1414c38

Last change on this file since 1421:7a21e1414c38 was 1421:7a21e1414c38, checked in by Balazs Dezso, 19 years ago

IO with undirected edgesets and undirected graphs.
Missing features:

InfoReader?,
aliased edges in undir edgesets

File size: 49.0 KB
Line 
1/* -*- C++ -*-
2 * src/lemon/lemon_reader.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 reader.
20
21
22#ifndef LEMON_LEMON_READER_H
23#define LEMON_LEMON_READER_H
24
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/graph_utils.h>
36#include <lemon/utility.h>
37#include <lemon/bits/item_reader.h>
38
39
40namespace lemon {
41
42  namespace _reader_bits {
43 
44    template <typename T>
45    bool operator<(T, T) {
46      throw DataFormatError("Id is not comparable");
47    }
48
49    template <typename T>
50    struct Less {
51      bool operator()(const T& p, const T& q) const {
52        return p < q;
53      }
54    };
55
56    template <typename M1, typename M2>
57    class WriteComposeMap {
58    public:
59      typedef True NeedCopy;
60     
61      typedef typename M2::Key Key;
62      typedef typename M1::Value Value;
63
64      WriteComposeMap(typename SmartParameter<M1>::Type _m1, const M2& _m2)
65        : m1(_m1), m2(_m2) {}
66     
67      void set(const Key& key, const Value& value) {
68        m1.set(m2[key], value);
69      }
70
71    private:
72     
73      typename SmartReference<M1>::Type m1;
74      typename SmartConstReference<M2>::Type m2;
75     
76    };
77
78    template <typename M1, typename M2>
79    WriteComposeMap<M1, M2> writeComposeMap(M1& m1, const M2& m2) {
80      return WriteComposeMap<M1, M2>(m1, m2);
81    }
82
83    template <typename M1, typename M2>
84    WriteComposeMap<M1, M2> writeComposeMap(const M1& m1, const M2& m2) {
85      return WriteComposeMap<M1, M2>(m1, m2);
86    }
87 
88  }
89
90  /// \ingroup io_group
91  /// \brief Lemon Format reader class.
92  ///
93  /// The Lemon Format contains several sections. We do not want to
94  /// determine what sections are in a lemon file we give only a framework
95  /// to read a section oriented format.
96  ///
97  /// In the Lemon Format each section starts with a line contains a \c \@
98  /// character on the first not white space position. This line is the
99  /// header line of the section. Each next lines belong to this section
100  /// while it does not starts with \c \@ character. This line can start a
101  /// new section or if it can close the file with the \c \@end line.
102  /// The file format ignore the empty lines and it may contain comments
103  /// started with a \c # character to the end of the line.
104  ///
105  /// The framework provides an abstract LemonReader::SectionReader class
106  /// what defines the interface of a SectionReader. The SectionReader
107  /// has the \c header() member function what get a header line string and
108  /// decides if it want to process the next section. Several SectionReaders
109  /// can be attached to an LemonReader and the first attached what can
110  /// process the section will be used. Its \c read() member will called
111  /// with a stream contains the section. From this stream the empty lines
112  /// and comments are filtered out.
113  ///
114  /// \relates GraphReader
115  /// \relates NodeSetReader
116  /// \relates EdgeSetReader
117  /// \relates NodesReader
118  /// \relates EdgesReader
119  /// \relates AttributeReader
120  class LemonReader {
121  private:
122   
123    class FilterStreamBuf : public std::streambuf {
124    public:
125
126      typedef std::streambuf Parent;
127      typedef Parent::char_type char_type;
128      FilterStreamBuf(std::istream& is, int& num)
129        : _is(is), _base(0), _eptr(0),
130          _num(num), skip_state(after_endl) {}
131
132    protected:
133
134      enum skip_state_type {
135        no_skip,
136        after_comment,
137        after_endl,
138        empty_line
139      };
140
141      char_type small_buf[1];
142
143
144      std::istream& _is;
145
146      char_type* _base;
147      char_type* _eptr;
148
149      int& _num;
150
151      skip_state_type skip_state;
152
153
154      char_type* base() { return _base; }
155
156      char_type* eptr() { return _eptr; }
157
158      int blen() { return _eptr - _base; }
159
160      void setb(char_type* buf, int len) {
161        _base = buf;
162        _eptr = buf + len;
163      }
164 
165      virtual std::streambuf* setbuf(char *buf, int len) {
166        if (base()) return 0;
167        if (buf != 0 && len >= (int)sizeof(small_buf)) {
168          setb(buf, len);
169        } else {
170          setb(small_buf, sizeof(small_buf));
171        }
172        setg(0, 0, 0);
173        return this;
174      }
175
176      bool put_char(char c) {
177        switch (skip_state) {
178        case no_skip:
179          switch (c) {
180          case '\n':
181            skip_state = after_endl;
182            return true;
183          case '#':
184            skip_state = after_comment;
185            return false;
186          default:
187            return true;
188          }
189        case after_comment:
190          switch (c) {
191          case '\n':
192            skip_state = after_endl;
193            return true;
194          default:
195            return false;
196          }       
197        case after_endl:
198          switch (c) {
199          case '@':
200            return false;
201          case '\n':
202            return false;
203          case '#':
204            skip_state = empty_line;
205            return false;
206          default:
207            if (!isspace(c)) {
208              skip_state = no_skip;
209              return true;
210            } else {
211              return false;
212            }
213          }
214          break;
215        case empty_line:
216          switch (c) {
217          case '\n':
218            skip_state = after_endl;
219            return false;
220          default:
221            return false;
222          }
223        }
224        return false;
225      }
226
227      virtual int underflow() {
228        char c;
229        if (_is.read(&c, 1)) {
230          _is.putback(c);
231          if (c == '@') {
232            return EOF;
233          }
234        } else {
235          return EOF;
236        }
237        char_type *ptr;
238        for (ptr = base(); ptr != eptr(); ++ptr) {
239          if (_is.read(&c, 1)) {
240            if (c == '\n') ++_num;
241            if (put_char(c)) {
242              *ptr = c;
243            } else {
244              if (skip_state == after_endl && c == '@') {
245                _is.putback('@');
246                break;
247              }
248              --ptr;
249            }
250          } else {
251            break;
252          }
253        }
254        setg(base(), base(), ptr);
255        return *base();
256      }
257
258      virtual int sync() {
259        return EOF;
260      }
261    };
262
263  public:
264
265    /// \brief Abstract base class for reading a section.
266    ///
267    /// This class has an \c header() member function what get a
268    /// header line string and decides if it want to process the next
269    /// section. Several SectionReaders can be attached to an LemonReader
270    /// and the first attached what can process the section will be used.
271    /// Its \c read() member will called with a stream contains the section.
272    /// From this stream the empty lines and comments are filtered out.
273    class SectionReader {
274      friend class LemonReader;
275    protected:
276      /// \brief Constructor for SectionReader.
277      ///
278      /// Constructor for SectionReader. It attach this reader to
279      /// the given LemonReader.
280      SectionReader(LemonReader& reader) {
281        reader.attach(*this);
282      }
283
284      /// \brief Gives back true when the SectionReader can process
285      /// the section with the given header line.
286      ///
287      /// It gives back true when the SectionReader can process
288      /// the section with the given header line.
289      virtual bool header(const std::string& line) = 0;
290
291      /// \brief Reader function of the section.
292      ///
293      /// It reads the content of the section.
294      virtual void read(std::istream& is) = 0;
295    };
296
297    /// \brief Constructor for LemonReader.
298    ///
299    /// Constructor for LemonReader which reads from the given stream.
300    LemonReader(std::istream& _is)
301      : is(&_is), own_is(false) {}
302
303    /// \brief Constructor for LemonReader.
304    ///
305    /// Constructor for LemonReader which reads from the given file.
306    LemonReader(const std::string& filename)
307      : is(0), own_is(true) {
308      is = new std::ifstream(filename.c_str());
309    }
310
311    /// \brief Desctructor for LemonReader.
312    ///
313    /// Desctructor for LemonReader.
314    ~LemonReader() {
315      if (own_is) {
316        delete is;
317      }
318    }
319
320  private:
321    LemonReader(const LemonReader&);
322    void operator=(const LemonReader&);
323
324    void attach(SectionReader& reader) {
325      readers.push_back(&reader);
326    }
327
328  public:
329    /// \brief Executes the LemonReader.
330    ///
331    /// It executes the LemonReader.
332    void run() {
333      int line_num = 0;
334      std::string line;
335      try {
336        while ((++line_num, getline(*is, line)) && line.find("@end") != 0) {
337          SectionReaders::iterator it;
338          for (it = readers.begin(); it != readers.end(); ++it) {
339            if ((*it)->header(line)) {
340              char buf[2048];
341              FilterStreamBuf buffer(*is, line_num);
342              buffer.pubsetbuf(buf, sizeof(buf));
343              std::istream is(&buffer);
344              (*it)->read(is);
345              break;
346            }
347          }
348        }
349      } catch (DataFormatError& error) {
350        error.line(line_num);
351        throw error;
352      }
353    }
354
355
356  private:
357
358    std::istream* is;
359    bool own_is;
360
361    typedef std::vector<SectionReader*> SectionReaders;
362    SectionReaders readers;
363
364  };
365
366  /// \brief Helper class for implementing the common SectionReaders.
367  ///
368  /// Helper class for implementing the common SectionReaders.
369  class CommonSectionReaderBase : public LemonReader::SectionReader {
370    typedef LemonReader::SectionReader Parent;
371  protected:
372   
373    /// \brief Constructor for CommonSectionReaderBase.
374    ///
375    /// Constructor for CommonSectionReaderBase. It attach this reader to
376    /// the given LemonReader.
377    CommonSectionReaderBase(LemonReader& _reader)
378      : Parent(_reader) {}
379
380    template <typename _Item>
381    class ReaderBase;
382   
383    template <typename _Item>
384    class InverterBase : public ReaderBase<_Item> {
385    public:
386      typedef _Item Item;
387      virtual void read(std::istream&, const Item&) = 0;
388      virtual Item read(std::istream&) const = 0;
389
390      virtual InverterBase<_Item>* getInverter() {
391        return this;
392      }
393    };
394
395    template <typename _Item, typename _Map, typename _Reader>
396    class MapReaderInverter : public InverterBase<_Item> {
397    public:
398      typedef _Item Item;
399      typedef _Reader Reader;
400      typedef typename Reader::Value Value;
401      typedef _Map Map;
402      typedef std::map<Value, Item,
403                       typename _reader_bits::template Less<Value> > Inverse;
404
405      typename SmartReference<Map>::Type map;
406      Reader reader;
407      Inverse inverse;
408
409      MapReaderInverter(typename SmartParameter<Map>::Type _map,
410                        const Reader& _reader)
411        : map(_map), reader(_reader) {}
412
413      virtual ~MapReaderInverter() {}
414
415      virtual void read(std::istream& is, const Item& item) {
416        Value value;
417        reader.read(is, value);
418        map.set(item, value);
419        typename Inverse::iterator it = inverse.find(value);
420        if (it == inverse.end()) {
421          inverse.insert(std::make_pair(value, item));
422        } else {
423          throw DataFormatError("Multiple ID occurence");
424        }
425      }
426
427      virtual Item read(std::istream& is) const {
428        Value value;
429        reader.read(is, value);
430        typename Inverse::const_iterator it = inverse.find(value);
431        if (it != inverse.end()) {
432          return it->second;
433        } else {
434          throw DataFormatError("Invalid ID error");
435        }
436      }     
437    };
438
439    template <typename _Item, typename _Reader>
440    class SkipReaderInverter : public InverterBase<_Item> {
441    public:
442      typedef _Item Item;
443      typedef _Reader Reader;
444      typedef typename Reader::Value Value;
445      typedef std::map<Value, Item,
446                       typename _reader_bits::template Less<Value> > Inverse;
447
448      Reader reader;
449
450      SkipReaderInverter(const Reader& _reader)
451        : reader(_reader) {}
452
453      virtual ~SkipReaderInverter() {}
454
455      virtual void read(std::istream& is, const Item& item) {
456        Value value;
457        reader.read(is, value);
458        typename Inverse::iterator it = inverse.find(value);
459        if (it == inverse.end()) {
460          inverse.insert(std::make_pair(value, item));
461        } else {
462          throw DataFormatError("Multiple ID occurence error");
463        }
464      }
465
466      virtual Item read(std::istream& is) const {
467        Value value;
468        reader.read(is, value);
469        typename Inverse::const_iterator it = inverse.find(value);
470        if (it != inverse.end()) {
471          return it->second;
472        } else {
473          throw DataFormatError("Invalid ID error");
474        }
475      }
476
477    private:
478      Inverse inverse;
479    };
480
481    template <typename _Item>   
482    class ReaderBase {
483    public:
484      typedef _Item Item;
485
486      virtual ~ReaderBase() {}
487
488      virtual void read(std::istream& is, const Item& item) = 0;
489      virtual InverterBase<_Item>* getInverter() = 0;
490    };
491
492    template <typename _Item, typename _Map, typename _Reader>
493    class MapReader : public ReaderBase<_Item> {
494    public:
495      typedef _Map Map;
496      typedef _Reader Reader;
497      typedef typename Reader::Value Value;
498      typedef _Item Item;
499     
500      typename SmartReference<Map>::Type map;
501      Reader reader;
502
503      MapReader(typename SmartParameter<Map>::Type _map,
504                const Reader& _reader)
505        : map(_map), reader(_reader) {}
506
507      virtual ~MapReader() {}
508
509      virtual void read(std::istream& is, const Item& item) {
510        Value value;
511        reader.read(is, value);
512        map.set(item, value);
513      }
514
515      virtual InverterBase<_Item>* getInverter() {
516        return new MapReaderInverter<Item, Map, Reader>(map, reader);
517      }
518    };
519
520
521    template <typename _Item, typename _Reader>
522    class SkipReader : public ReaderBase<_Item> {
523    public:
524      typedef _Reader Reader;
525      typedef typename Reader::Value Value;
526      typedef _Item Item;
527
528      Reader reader;
529      SkipReader(const Reader& _reader) : reader(_reader) {}
530
531      virtual ~SkipReader() {}
532
533      virtual void read(std::istream& is, const Item&) {
534        Value value;
535        reader.read(is, value);
536      }     
537
538      virtual InverterBase<Item>* getInverter() {
539        return new SkipReaderInverter<Item, Reader>(reader);
540      }
541    };
542
543    template <typename _Item>
544    class IdReaderBase {
545    public:
546      typedef _Item Item;
547      virtual Item read(std::istream& is) const = 0;
548    };
549
550    template <typename _Item, typename _BoxedIdReader>
551    class IdReader : public IdReaderBase<_Item> {
552    public:
553      typedef _Item Item;
554      typedef _BoxedIdReader BoxedIdReader;
555     
556      const BoxedIdReader& boxedIdReader;
557
558      IdReader(const BoxedIdReader& _boxedIdReader)
559        : boxedIdReader(_boxedIdReader) {}
560
561      virtual Item read(std::istream& is) const {
562        return boxedIdReader.readId(is);
563      }
564    };
565
566    class ValueReaderBase {
567    public:
568      virtual void read(std::istream&) {};
569    };
570
571    template <typename _Value, typename _Reader>
572    class ValueReader : public ValueReaderBase {
573    public:
574      typedef _Value Value;
575      typedef _Reader Reader;
576
577      ValueReader(Value& _value, const Reader& _reader)
578        : value(_value), reader(_reader) {}
579
580      virtual void read(std::istream& is) {
581        reader.read(is, value);
582      }
583    private:
584      Value& value;
585      Reader reader;
586    };
587   
588  };
589
590  /// \ingroup io_group
591  /// \brief SectionReader for reading a graph's nodeset.
592  ///
593  /// The lemon format can store multiple graph nodesets with several maps.
594  /// The nodeset section's header line is \c \@nodeset \c nodeset_id, but the
595  /// \c nodeset_id may be empty.
596  ///
597  /// The first line of the section contains the names of the maps separated
598  /// with white spaces. Each next lines describes a node in the nodeset, and
599  /// contains the mapped values for each map.
600  ///
601  /// If the nodeset contains an \c "id" named map then it will be regarded
602  /// as id map. This map should contain only unique values and when the
603  /// \c readId() member will read a value from the given stream it will
604  /// give back that node which is mapped to this value.
605  ///
606  /// \relates LemonReader
607  template <typename _Graph, typename _Traits = DefaultReaderTraits>
608  class NodeSetReader : public CommonSectionReaderBase {
609    typedef CommonSectionReaderBase Parent;
610  public:
611
612    typedef _Graph Graph;
613    typedef _Traits Traits;
614    typedef typename Graph::Node Item;
615    typedef typename Traits::Skipper DefaultSkipper;
616
617    /// \brief Constructor.
618    ///
619    /// Constructor for NodeSetReader. It creates the NodeSetReader and
620    /// attach it into the given LemonReader. The nodeset reader will
621    /// add the readed nodes to the given Graph. The reader will read
622    /// the section when the \c section_id and the \c _id are the same.
623    NodeSetReader(LemonReader& _reader,
624                  typename SmartParameter<Graph>::Type _graph,
625                  const std::string& _id = std::string(),
626                  const DefaultSkipper& _skipper = DefaultSkipper())
627      : Parent(_reader), graph(_graph), id(_id), skipper(_skipper) {}
628
629
630    /// \brief Destructor.
631    ///
632    /// Destructor for NodeSetReader.
633    virtual ~NodeSetReader() {
634      for (typename MapReaders::iterator it = readers.begin();
635           it != readers.end(); ++it) {
636        delete it->second;
637      }
638    }
639
640  private:
641    NodeSetReader(const NodeSetReader&);
642    void operator=(const NodeSetReader&);
643 
644  public:
645
646    /// \brief Add a new node map reader command for the reader.
647    ///
648    /// Add a new node map reader command for the reader.
649    template <typename Map>
650    NodeSetReader& readNodeMap(std::string name, Map& map) {
651      return _readMap<
652        typename Traits::template Reader<typename Map::Value>, Map,
653        typename SmartParameter<Map>::Type>(name, map);
654    }
655
656    template <typename Map>
657    NodeSetReader& readNodeMap(std::string name, const Map& map) {
658      return _readMap<
659        typename Traits::template Reader<typename Map::Value>, Map,
660        typename SmartParameter<Map>::Type>(name, map);
661    }
662
663    /// \brief Add a new node map reader command for the reader.
664    ///
665    /// Add a new node map reader command for the reader.
666    template <typename Reader, typename Map>
667    NodeSetReader& readNodeMap(std::string name, Map& map,
668                               const Reader& reader = Reader()) {
669      return _readMap<
670        typename Traits::template Reader<typename Map::Value>, Map,
671        typename SmartParameter<Map>::Type>(name, map, reader);
672    }
673
674    template <typename Reader, typename Map>
675    NodeSetReader& readNodeMap(std::string name, const Map& map,
676                               const Reader& reader = Reader()) {
677      return _readMap<
678        typename Traits::template Reader<typename Map::Value>, Map,
679        typename SmartParameter<Map>::Type>(name, map, reader);
680    }
681
682  private:
683
684    template <typename Reader, typename Map, typename MapParameter>
685    NodeSetReader& _readMap(std::string name, MapParameter map,
686                            const Reader& reader = Reader()) {
687      if (readers.find(name) != readers.end()) {
688        ErrorMessage msg;
689        msg << "Multiple read rule for node map: " << name;
690        throw IOParameterError(msg.message());
691      }
692      readers.insert(
693        make_pair(name, new MapReader<Item, Map, Reader>(map, reader)));
694      return *this;
695    }
696
697  public:
698
699    /// \brief Add a new node map skipper command for the reader.
700    ///
701    /// Add a new node map skipper command for the reader.
702    template <typename Reader>
703    NodeSetReader& skipNodeMap(std::string name,
704                           const Reader& reader = Reader()) {
705      if (readers.find(name) != readers.end()) {
706        ErrorMessage msg;
707        msg << "Multiple read rule for node map: " << name;
708        throw IOParameterError(msg.message());
709      }
710      readers.insert(make_pair(name, new SkipReader<Item, Reader>(reader)));
711      return *this;
712    }
713
714  protected:
715
716    /// \brief Gives back true when the SectionReader can process
717    /// the section with the given header line.
718    ///
719    /// It gives back true when the header line starts with \c \@nodeset,
720    /// and the header line's id and the nodeset's id are the same.
721    virtual bool header(const std::string& line) {
722      std::istringstream ls(line);
723      std::string command;
724      std::string name;
725      ls >> command >> name;
726      return command == "@nodeset" && name == id;
727    }
728
729    /// \brief Reader function of the section.
730    ///
731    /// It reads the content of the section.
732    virtual void read(std::istream& is) {
733      std::vector<ReaderBase<Item>* > index;
734      std::string line;
735
736      getline(is, line);
737      std::istringstream ls(line);     
738      while (ls >> id) {
739        typename MapReaders::iterator it = readers.find(id);
740        if (it != readers.end()) {
741          index.push_back(it->second);
742        } else {
743          index.push_back(&skipper);
744        }
745        if (id == "id" && inverter.get() == 0) {
746          inverter.reset(index.back()->getInverter());
747          index.back() = inverter.get();
748        }
749      }
750      while (getline(is, line)) {       
751        typename Graph::Node node = graph.addNode();
752        std::istringstream ls(line);
753        for (int i = 0; i < (int)index.size(); ++i) {
754          index[i]->read(ls, node);
755        }
756      }
757    }
758
759  public:
760
761    /// \brief Returns true if the nodeset can give back the node by its id.
762    ///
763    /// Returns true if the nodeset can give back the node by its id.
764    /// It is possible only if an "id" named map was read.
765    bool isIdReader() const {
766      return inverter.get() != 0;
767    }
768
769    /// \brief Gives back the node by its id.
770    ///
771    /// It reads an id from the stream and gives back which node belongs to
772    /// it. It is possible only if there was read an "id" named map.
773    Item readId(std::istream& is) const {
774      return inverter->read(is);
775    }
776
777  private:
778
779    typedef std::map<std::string, ReaderBase<Item>*> MapReaders;
780    MapReaders readers;
781   
782    typename SmartReference<Graph>::Type graph;   
783    std::string id;
784    SkipReader<Item, DefaultSkipper> skipper;
785
786    std::auto_ptr<InverterBase<Item> > inverter;
787  };
788
789  /// \ingroup io_group
790  /// \brief SectionReader for reading a graph's edgeset.
791  ///
792  /// The lemon format can store multiple graph edgesets with several maps.
793  /// The edgeset section's header line is \c \@edgeset \c edgeset_id, but the
794  /// \c edgeset_id may be empty.
795  ///
796  /// The first line of the section contains the names of the maps separated
797  /// with white spaces. Each next lines describes an edge in the edgeset. The
798  /// line contains the source and the target nodes' id and the mapped
799  /// values for each map.
800  ///
801  /// If the edgeset contains an \c "id" named map then it will be regarded
802  /// as id map. This map should contain only unique values and when the
803  /// \c readId() member will read a value from the given stream it will
804  /// give back that edge which is mapped to this value.
805  ///
806  /// The edgeset reader needs a node id reader to identify which nodes
807  /// have to be connected. If a NodeSetReader reads an "id" named map,
808  /// it will be able to resolve the nodes by ids.
809  ///
810  /// \relates LemonReader
811  template <typename _Graph, typename _Traits = DefaultReaderTraits>
812  class EdgeSetReader : public CommonSectionReaderBase {
813    typedef CommonSectionReaderBase Parent;
814  public:
815
816    typedef _Graph Graph;
817    typedef _Traits Traits;
818    typedef typename Graph::Edge Item;
819    typedef typename Traits::Skipper DefaultSkipper;
820
821    /// \brief Constructor.
822    ///
823    /// Constructor for EdgeSetReader. It creates the EdgeSetReader and
824    /// attach it into the given LemonReader. The edgeset reader will
825    /// add the readed edges to the given Graph. It will use the given
826    /// node id reader to read the source and target nodes of the edges.
827    /// The reader will read the section only if the \c _id and the
828    /// \c edgset_id are the same.
829    template <typename NodeIdReader>
830    EdgeSetReader(LemonReader& _reader,
831                  typename SmartParameter<Graph>::Type _graph,
832                  const NodeIdReader& _nodeIdReader,
833                  const std::string& _id = std::string(),
834                  const DefaultSkipper& _skipper = DefaultSkipper())
835      : Parent(_reader), graph(_graph), id(_id), skipper(_skipper),
836        nodeIdReader(new IdReader<typename Graph::Node, NodeIdReader>
837                     (_nodeIdReader)) {}
838
839    /// \brief Destructor.
840    ///
841    /// Destructor for EdgeSetReader.
842    virtual ~EdgeSetReader() {
843      for (typename MapReaders::iterator it = readers.begin();
844           it != readers.end(); ++it) {
845        delete it->second;
846      }
847    }
848
849  private:
850    EdgeSetReader(const EdgeSetReader&);
851    void operator=(const EdgeSetReader&);
852
853  public:
854
855    /// \brief Add a new edge map reader command for the reader.
856    ///
857    /// Add a new edge map reader command for the reader.
858    template <typename Map>
859    EdgeSetReader& readEdgeMap(std::string name, Map& map) {
860      return _readMap<
861        typename Traits::template Reader<typename Map::Value>, Map,
862        typename SmartParameter<Map>::Type>(name, map);
863    }
864
865    template <typename Map>
866    EdgeSetReader& readEdgeMap(std::string name, const Map& map) {
867      return _readMap<
868        typename Traits::template Reader<typename Map::Value>, Map,
869        typename SmartParameter<Map>::Type>(name, map);
870    }
871
872    /// \brief Add a new edge map reader command for the reader.
873    ///
874    /// Add a new edge map reader command for the reader.
875    template <typename Reader, typename Map>
876    EdgeSetReader& readEdgeMap(std::string name, Map& map,
877                           const Reader& reader = Reader()) {
878      return _readMap<
879        typename Traits::template Reader<typename Map::Value>, Map,
880        typename SmartParameter<Map>::Type>(name, map, reader);
881    }
882
883    template <typename Reader, typename Map>
884    EdgeSetReader& readEdgeMap(std::string name, const Map& map,
885                               const Reader& reader = Reader()) {
886      return _readMap<
887        typename Traits::template Reader<typename Map::Value>, Map,
888        typename SmartParameter<Map>::Type>(name, map, reader);
889    }
890
891  private:
892
893    template <typename Reader, typename Map, typename MapParameter>
894    EdgeSetReader& _readMap(std::string name, MapParameter map,
895                            const Reader& reader = Reader()) {
896      if (readers.find(name) != readers.end()) {
897        ErrorMessage msg;
898        msg << "Multiple read rule for edge map: " << name;
899        throw IOParameterError(msg.message());
900      }
901      readers.insert(
902        make_pair(name, new MapReader<Item, Map, Reader>(map, reader)));
903      return *this;
904    }
905
906  public:
907
908    /// \brief Add a new edge map skipper command for the reader.
909    ///
910    /// Add a new edge map skipper command for the reader.
911    template <typename Reader>
912    EdgeSetReader& skipEdgeMap(std::string name,
913                               const Reader& reader = Reader()) {
914      if (readers.find(name) != readers.end()) {
915        ErrorMessage msg;
916        msg << "Multiple read rule for edge map: " << name;
917        throw IOParameterError(msg.message());
918      }
919      readers.insert(make_pair(name, new SkipReader<Item, Reader>(reader)));
920      return *this;
921    }
922
923  protected:
924
925    /// \brief Gives back true when the SectionReader can process
926    /// the section with the given header line.
927    ///
928    /// It gives back true when the header line starts with \c \@edgeset,
929    /// and the header line's id and the edgeset's id are the same.
930    virtual bool header(const std::string& line) {
931      std::istringstream ls(line);
932      std::string command;
933      std::string name;
934      ls >> command >> name;
935      return command == "@edgeset" && name == id;
936    }
937
938    /// \brief Reader function of the section.
939    ///
940    /// It reads the content of the section.
941    virtual void read(std::istream& is) {
942      std::vector<ReaderBase<Item>* > index;
943      std::string line;
944
945      getline(is, line);
946      std::istringstream ls(line);     
947      while (ls >> id) {
948        typename MapReaders::iterator it = readers.find(id);
949        if (it != readers.end()) {
950          index.push_back(it->second);
951        } else {
952          index.push_back(&skipper);
953        }
954        if (id == "id" && inverter.get() == 0) {
955          inverter.reset(index.back()->getInverter());
956          index.back() = inverter.get();
957        }
958      }
959      while (getline(is, line)) {       
960        std::istringstream ls(line);
961        typename Graph::Node from = nodeIdReader->read(ls);
962        typename Graph::Node to = nodeIdReader->read(ls);
963        typename Graph::Edge edge = graph.addEdge(from, to);
964        for (int i = 0; i < (int)index.size(); ++i) {
965          index[i]->read(ls, edge);
966        }
967      }
968    }
969
970  public:
971
972    /// \brief Returns true if the edgeset can give back the edge by its id.
973    ///
974    /// Returns true if the edgeset can give back the edge by its id.
975    /// It is possible only if an "id" named map was read.
976    bool isIdReader() const {
977      return inverter.get() != 0;
978    }
979
980    /// \brief Gives back the edge by its id.
981    ///
982    /// It reads an id from the stream and gives back which edge belongs to
983    /// it. It is possible only if there was read an "id" named map.
984    Item readId(std::istream& is) const {
985      return inverter->read(is);
986    }
987
988  private:
989
990    typedef std::map<std::string, ReaderBase<Item>*> MapReaders;
991    MapReaders readers;
992   
993    typename SmartReference<Graph>::Type graph;   
994    std::string id;
995    SkipReader<Item, DefaultSkipper> skipper;
996
997    std::auto_ptr<InverterBase<Item> > inverter;
998    std::auto_ptr<IdReaderBase<typename Graph::Node> > nodeIdReader;
999  };
1000
1001  /// \ingroup io_group
1002  /// \brief SectionReader for reading a undirected graph's edgeset.
1003  ///
1004  /// The lemon format can store multiple undirected edgesets with several
1005  /// maps. The undirected edgeset section's header line is \c \@undiredgeset
1006  /// \c undiredgeset_id, but the \c undiredgeset_id may be empty.
1007  ///
1008  /// The first line of the section contains the names of the maps separated
1009  /// with white spaces. Each next lines describes an edge in the edgeset. The
1010  /// line contains the connected nodes' id and the mapped values for each map.
1011  ///
1012  /// The section can handle the directed as a syntactical sugar. Two
1013  /// undirected edge map describes one directed edge map. This two maps
1014  /// are the forward map and the backward map and the names of this map
1015  /// is near the same just with a prefix \c '+' or \c '-' character
1016  /// difference.
1017  ///
1018  /// If the edgeset contains an \c "id" named map then it will be regarded
1019  /// as id map. This map should contain only unique values and when the
1020  /// \c readId() member will read a value from the given stream it will
1021  /// give back that undiricted edge which is mapped to this value.
1022  ///
1023  /// The undirected edgeset reader needs a node id reader to identify which
1024  /// nodes have to be connected. If a NodeSetReader reads an "id" named map,
1025  /// it will be able to resolve the nodes by ids.
1026  ///
1027  /// \relates LemonReader
1028  template <typename _Graph, typename _Traits = DefaultReaderTraits>
1029  class UndirEdgeSetReader : public CommonSectionReaderBase {
1030    typedef CommonSectionReaderBase Parent;
1031  public:
1032
1033    typedef _Graph Graph;
1034    typedef _Traits Traits;
1035    typedef typename Graph::UndirEdge Item;
1036    typedef typename Traits::Skipper DefaultSkipper;
1037
1038    /// \brief Constructor.
1039    ///
1040    /// Constructor for UndirEdgeSetReader. It creates the UndirEdgeSetReader
1041    /// and attach it into the given LemonReader. The undirected edgeset
1042    /// reader will add the readed undirected edges to the given Graph. It
1043    /// will use the given node id reader to read the source and target
1044    /// nodes of the edges. The reader will read the section only if the
1045    /// \c _id and the \c undiredgset_id are the same.
1046    template <typename NodeIdReader>
1047    UndirEdgeSetReader(LemonReader& _reader,
1048                       typename SmartParameter<Graph>::Type _graph,
1049                       const NodeIdReader& _nodeIdReader,
1050                       const std::string& _id = std::string(),
1051                       const DefaultSkipper& _skipper = DefaultSkipper())
1052      : Parent(_reader), graph(_graph), id(_id), skipper(_skipper),
1053        nodeIdReader(new IdReader<typename Graph::Node, NodeIdReader>
1054                     (_nodeIdReader)) {}
1055
1056    /// \brief Destructor.
1057    ///
1058    /// Destructor for UndirEdgeSetReader.
1059    virtual ~UndirEdgeSetReader() {
1060      for (typename MapReaders::iterator it = readers.begin();
1061           it != readers.end(); ++it) {
1062        delete it->second;
1063      }
1064    }
1065
1066  private:
1067    UndirEdgeSetReader(const UndirEdgeSetReader&);
1068    void operator=(const UndirEdgeSetReader&);
1069
1070  public:
1071
1072    /// \brief Add a new undirected edge map reader command for the reader.
1073    ///
1074    /// Add a new edge undirected map reader command for the reader.
1075    template <typename Map>
1076    UndirEdgeSetReader& readUndirEdgeMap(std::string name, Map& map) {
1077      return _readMap<
1078        typename Traits::template Reader<typename Map::Value>, Map,
1079        typename SmartParameter<Map>::Type>(name, map);
1080    }
1081
1082    template <typename Map>
1083    UndirEdgeSetReader& readUndirEdgeMap(std::string name, const Map& map) {
1084      return _readMap<
1085        typename Traits::template Reader<typename Map::Value>, Map,
1086        typename SmartParameter<Map>::Type>(name, map);
1087    }
1088
1089    /// \brief Add a new undirected edge map reader command for the reader.
1090    ///
1091    /// Add a new edge undirected map reader command for the reader.
1092    template <typename Reader, typename Map>
1093    UndirEdgeSetReader& readUndirEdgeMap(std::string name, Map& map,
1094                                         const Reader& reader = Reader()) {
1095      return _readMap<Reader, Map, typename SmartParameter<Map>::Type>
1096        (name, map, reader);
1097    }
1098
1099    template <typename Reader, typename Map>
1100    UndirEdgeSetReader& readUndirEdgeMap(std::string name, const Map& map,
1101                                         const Reader& reader = Reader()) {
1102      return _readMap<Reader, Map, typename SmartParameter<Map>::Type >
1103        (name, map, reader);
1104    }
1105
1106  private:
1107
1108    template <typename Reader, typename Map, typename MapParameter>
1109    UndirEdgeSetReader& _readMap(std::string name, MapParameter map,
1110                                 const Reader& reader = Reader()) {
1111      if (readers.find(name) != readers.end()) {
1112        ErrorMessage msg;
1113        msg << "Multiple read rule for edge map: " << name;
1114        throw IOParameterError(msg.message());
1115      }
1116      readers.insert(
1117        make_pair(name, new MapReader<Item, Map, Reader>(map, reader)));
1118      return *this;
1119    }
1120
1121  public:
1122
1123    /// \brief Add a new undirected edge map skipper command for the reader.
1124    ///
1125    /// Add a new undirected edge map skipper command for the reader.
1126    template <typename Reader>
1127    UndirEdgeSetReader& skipUndirEdgeMap(std::string name,
1128                                         const Reader& reader = Reader()) {
1129      if (readers.find(name) != readers.end()) {
1130        ErrorMessage msg;
1131        msg << "Multiple read rule for node map: " << name;
1132        throw IOParameterError(msg.message());
1133      }
1134      readers.insert(make_pair(name, new SkipReader<Item, Reader>(reader)));
1135      return *this;
1136    }
1137
1138    /// \brief Add a new directed edge map reader command for the reader.
1139    ///
1140    /// Add a new directed edge map reader command for the reader.
1141    template <typename Map>
1142    UndirEdgeSetReader& readEdgeMap(std::string name, Map& map) {
1143      return _readDirMap<
1144        typename Traits::template Reader<typename Map::Value>, Map,
1145        typename SmartParameter<Map>::Type>(name, map);
1146    }
1147
1148    template <typename Map>
1149    UndirEdgeSetReader& readEdgeMap(std::string name, const Map& map) {
1150      return _readDirMap<
1151        typename Traits::template Reader<typename Map::Value>, Map,
1152        typename SmartParameter<Map>::Type>(name, map);
1153    }
1154
1155    /// \brief Add a new directed edge map reader command for the reader.
1156    ///
1157    /// Add a new directed edge map reader command for the reader.
1158    template <typename Reader, typename Map>
1159    UndirEdgeSetReader& readEdgeMap(std::string name, Map& map,
1160                                    const Reader& reader = Reader()) {
1161      return _readDirMap<Reader, Map, typename SmartParameter<Map>::Type>
1162        (name, map, reader);
1163    }
1164
1165    template <typename Reader, typename Map>
1166    UndirEdgeSetReader& readEdgeMap(std::string name, const Map& map,
1167                                    const Reader& reader = Reader()) {
1168      return _readDirMap<Reader, Map, typename SmartParameter<Map>::Type>
1169        (name, map, reader);
1170    }
1171
1172  private:
1173
1174    template <typename Reader, typename Map, typename MapParameter>
1175    UndirEdgeSetReader& _readDirMap(std::string name, MapParameter map,
1176                                    const Reader& reader = Reader()) {
1177      readMap("+" + name,
1178              _reader_bits::writeComposeMap(map, forwardMap(graph)), reader);
1179      readMap("-" + name,
1180              _reader_bits::writeComposeMap(map, backwardMap(graph)), reader);
1181      return *this;     
1182    }
1183
1184  public:
1185
1186    /// \brief Add a new directed edge map skipper command for the reader.
1187    ///
1188    /// Add a new directed edge map skipper command for the reader.
1189    template <typename Reader>
1190    UndirEdgeSetReader& skipEdgeMap(std::string name,
1191                                    const Reader& reader = Reader()) {
1192      skipMap("+" + name, reader);
1193      skipMap("-" + name, reader);
1194      return *this;
1195    }
1196
1197  protected:
1198
1199    /// \brief Gives back true when the SectionReader can process
1200    /// the section with the given header line.
1201    ///
1202    /// It gives back true when the header line starts with \c \@undiredgeset,
1203    /// and the header line's id and the edgeset's id are the same.
1204    virtual bool header(const std::string& line) {
1205      std::istringstream ls(line);
1206      std::string command;
1207      std::string name;
1208      ls >> command >> name;
1209      return command == "@undiredgeset" && name == id;
1210    }
1211
1212    /// \brief Reader function of the section.
1213    ///
1214    /// It reads the content of the section.
1215    virtual void read(std::istream& is) {
1216      std::vector<ReaderBase<Item>* > index;
1217      std::string line;
1218
1219      getline(is, line);
1220      std::istringstream ls(line);     
1221      while (ls >> id) {
1222        typename MapReaders::iterator it = readers.find(id);
1223        if (it != readers.end()) {
1224          index.push_back(it->second);
1225        } else {
1226          index.push_back(&skipper);
1227        }
1228        if (id == "id" && inverter.get() == 0) {
1229          inverter.reset(index.back()->getInverter());
1230          index.back() = inverter.get();
1231        }
1232      }
1233      while (getline(is, line)) {       
1234        std::istringstream ls(line);
1235        typename Graph::Node from = nodeIdReader->read(ls);
1236        typename Graph::Node to = nodeIdReader->read(ls);
1237        typename Graph::UndirEdge edge = graph.addEdge(from, to);
1238        for (int i = 0; i < (int)index.size(); ++i) {
1239          index[i]->read(ls, edge);
1240        }
1241      }
1242    }
1243
1244  public:
1245
1246    /// \brief Returns true if the edgeset can give back the edge by its id.
1247    ///
1248    /// Returns true if the edgeset can give back the undirected edge by its
1249    /// id. It is possible only if an "id" named map was read.
1250    bool isIdReader() const {
1251      return inverter.get() != 0;
1252    }
1253
1254    /// \brief Gives back the undirected edge by its id.
1255    ///
1256    /// It reads an id from the stream and gives back which undirected edge
1257    /// belongs to it. It is possible only if there was read an "id" named map.
1258    Item readId(std::istream& is) const {
1259      return inverter->read(is);
1260    }
1261
1262  private:
1263
1264    typedef std::map<std::string, ReaderBase<Item>*> MapReaders;
1265    MapReaders readers;
1266   
1267    typename SmartReference<Graph>::Type graph;   
1268    std::string id;
1269    SkipReader<Item, DefaultSkipper> skipper;
1270
1271    std::auto_ptr<InverterBase<Item> > inverter;
1272    std::auto_ptr<IdReaderBase<typename Graph::Node> > nodeIdReader;
1273  };
1274
1275  /// \ingroup io_group
1276  /// \brief SectionReader for reading labeled nodes.
1277  ///
1278  /// The nodes section's header line is \c \@nodes \c nodes_id, but the
1279  /// \c nodes_id may be empty.
1280  ///
1281  /// Each line in the section contains the name of the node
1282  /// and then the node id.
1283  ///
1284  /// \relates LemonReader
1285  template <typename _Graph>
1286  class NodeReader : public CommonSectionReaderBase {
1287    typedef CommonSectionReaderBase Parent;
1288    typedef _Graph Graph;
1289    typedef typename Graph::Node Item;
1290  public:
1291   
1292    /// \brief Constructor.
1293    ///
1294    /// Constructor for NodeReader. It creates the NodeReader and
1295    /// attach it into the given LemonReader. It will use the given
1296    /// node id reader to give back the nodes. The reader will read the
1297    /// section only if the \c _id and the \c nodes_id are the same.
1298    template <typename _IdReader>
1299    NodeReader(LemonReader& _reader, const _IdReader& _idReader,
1300               const std::string& _id = std::string())
1301      : Parent(_reader), id(_id),
1302        idReader(new IdReader<typename Graph::Node, _IdReader>(_idReader)) {}
1303
1304    /// \brief Destructor.
1305    ///
1306    /// Destructor for NodeReader.
1307    virtual ~NodeReader() {}
1308
1309  private:
1310    NodeReader(const NodeReader&);
1311    void operator=(const NodeReader&);
1312
1313  public:
1314
1315    /// \brief Add a node reader command for the NodeReader.
1316    ///
1317    /// Add a node reader command for the NodeReader.
1318    void readNode(const std::string& name, Item& item) {
1319      if (readers.find(name) != readers.end()) {
1320        ErrorMessage msg;
1321        msg << "Multiple read rule for node: " << name;
1322        throw IOParameterError(msg.message());
1323      }
1324      readers.insert(make_pair(name, &item));
1325    }
1326
1327  protected:
1328
1329    /// \brief Gives back true when the SectionReader can process
1330    /// the section with the given header line.
1331    ///
1332    /// It gives back true when the header line start with \c \@nodes,
1333    /// and the header line's id and the reader's id are the same.
1334    virtual bool header(const std::string& line) {
1335      std::istringstream ls(line);
1336      std::string command;
1337      std::string name;
1338      ls >> command >> name;
1339      return command == "@nodes" && name == id;
1340    }
1341
1342    /// \brief Reader function of the section.
1343    ///
1344    /// It reads the content of the section.
1345    virtual void read(std::istream& is) {
1346      std::string line;
1347      while (getline(is, line)) {
1348        std::istringstream ls(line);
1349        std::string id;
1350        ls >> id;
1351        typename ItemReaders::iterator it = readers.find(id);
1352        if (it != readers.end()) {
1353          *(it->second) = idReader->read(ls);
1354        }       
1355      }
1356    }
1357   
1358  private:
1359
1360    std::string id;
1361
1362    typedef std::map<std::string, Item*> ItemReaders;
1363    ItemReaders readers;
1364    std::auto_ptr<IdReaderBase<Item> > idReader;
1365  };
1366
1367  /// \ingroup io_group
1368  /// \brief SectionReader for reading labeled edges.
1369  ///
1370  /// The edges section's header line is \c \@edges \c edges_id, but the
1371  /// \c edges_id may be empty.
1372  ///
1373  /// Each line in the section contains the name of the edge
1374  /// and then the edge id.
1375  ///
1376  /// \relates LemonReader
1377  template <typename _Graph>
1378  class EdgeReader : public CommonSectionReaderBase {
1379    typedef CommonSectionReaderBase Parent;
1380    typedef _Graph Graph;
1381    typedef typename Graph::Edge Item;
1382  public:
1383   
1384    /// \brief Constructor.
1385    ///
1386    /// Constructor for EdgeReader. It creates the EdgeReader and
1387    /// attach it into the given LemonReader. It will use the given
1388    /// edge id reader to give back the edges. The reader will read the
1389    /// section only if the \c _id and the \c edges_id are the same.
1390    template <typename _IdReader>
1391    EdgeReader(LemonReader& _reader, const _IdReader& _idReader,
1392               const std::string& _id = std::string())
1393      : Parent(_reader), id(_id),
1394        idReader(new IdReader<typename Graph::Edge, _IdReader>(_idReader)) {}
1395
1396    /// \brief Destructor.
1397    ///
1398    /// Destructor for EdgeReader.
1399    virtual ~EdgeReader() {}
1400  private:
1401    EdgeReader(const EdgeReader&);
1402    void operator=(const EdgeReader&);
1403
1404  public:
1405
1406    /// \brief Add an edge reader command for the EdgeReader.
1407    ///
1408    /// Add an edge reader command for the EdgeReader.
1409    void readEdge(const std::string& name, Item& item) {
1410      if (readers.find(name) != readers.end()) {
1411        ErrorMessage msg;
1412        msg << "Multiple read rule for edge: " << name;
1413        throw IOParameterError(msg.message());
1414      }
1415      readers.insert(make_pair(name, &item));
1416    }
1417
1418  protected:
1419
1420    /// \brief Gives back true when the SectionReader can process
1421    /// the section with the given header line.
1422    ///
1423    /// It gives back true when the header line start with \c \@edges,
1424    /// and the header line's id and the reader's id are the same.
1425    virtual bool header(const std::string& line) {
1426      std::istringstream ls(line);
1427      std::string command;
1428      std::string name;
1429      ls >> command >> name;
1430      return command == "@edges" && name == id;
1431    }
1432
1433    /// \brief Reader function of the section.
1434    ///
1435    /// It reads the content of the section.
1436    virtual void read(std::istream& is) {
1437      std::string line;
1438      while (getline(is, line)) {
1439        std::istringstream ls(line);
1440        std::string id;
1441        ls >> id;
1442        typename ItemReaders::iterator it = readers.find(id);
1443        if (it != readers.end()) {
1444          *(it->second) = idReader->read(ls);
1445        }       
1446      }
1447    }
1448   
1449  private:
1450
1451    std::string id;
1452
1453    typedef std::map<std::string, Item*> ItemReaders;
1454    ItemReaders readers;
1455    std::auto_ptr<IdReaderBase<Item> > idReader;
1456  };
1457
1458  /// \ingroup io_group
1459  /// \brief SectionReader for reading labeled undirected edges.
1460  ///
1461  /// The undirected edges section's header line is \c \@undiredges
1462  /// \c undiredges_id, but the \c undiredges_id may be empty.
1463  ///
1464  /// Each line in the section contains the name of the undirected edge
1465  /// and then the undirected edge id.
1466  ///
1467  /// \relates LemonReader
1468  template <typename _Graph>
1469  class UndirEdgeReader : public CommonSectionReaderBase {
1470    typedef CommonSectionReaderBase Parent;
1471    typedef _Graph Graph;
1472    typedef typename Graph::UndirEdge Item;
1473  public:
1474   
1475    /// \brief Constructor.
1476    ///
1477    /// Constructor for UndirEdgeReader. It creates the UndirEdgeReader and
1478    /// attach it into the given LemonReader. It will use the given
1479    /// undirected edge id reader to give back the edges. The reader will
1480    /// read the section only if the \c _id and the \c undiredges_id are
1481    /// the same.
1482    template <typename _IdReader>
1483    UndirEdgeReader(LemonReader& _reader, const _IdReader& _idReader,
1484               const std::string& _id = std::string())
1485      : Parent(_reader), id(_id),
1486        idReader(new IdReader<typename Graph::UndirEdge, _IdReader>(_idReader))
1487    {}
1488
1489    /// \brief Destructor.
1490    ///
1491    /// Destructor for UndirEdgeReader.
1492    virtual ~UndirEdgeReader() {}
1493  private:
1494    UndirEdgeReader(const UndirEdgeReader&);
1495    void operator=(const UndirEdgeReader&);
1496
1497  public:
1498
1499    /// \brief Add an undirected edge reader command for the UndirEdgeReader.
1500    ///
1501    /// Add an undirected edge reader command for the UndirEdgeReader.
1502    void readUndirEdge(const std::string& name, Item& item) {
1503      if (readers.find(name) != readers.end()) {
1504        ErrorMessage msg;
1505        msg << "Multiple read rule for edge: " << name;
1506        throw IOParameterError(msg.message());
1507      }
1508      readers.insert(make_pair(name, &item));
1509    }
1510
1511  protected:
1512
1513    /// \brief Gives back true when the SectionReader can process
1514    /// the section with the given header line.
1515    ///
1516    /// It gives back true when the header line start with \c \@edges,
1517    /// and the header line's id and the reader's id are the same.
1518    virtual bool header(const std::string& line) {
1519      std::istringstream ls(line);
1520      std::string command;
1521      std::string name;
1522      ls >> command >> name;
1523      return command == "@edges" && name == id;
1524    }
1525
1526    /// \brief Reader function of the section.
1527    ///
1528    /// It reads the content of the section.
1529    virtual void read(std::istream& is) {
1530      std::string line;
1531      while (getline(is, line)) {
1532        std::istringstream ls(line);
1533        std::string id;
1534        ls >> id;
1535        typename ItemReaders::iterator it = readers.find(id);
1536        if (it != readers.end()) {
1537          *(it->second) = idReader->read(ls);
1538        }       
1539      }
1540    }
1541   
1542  private:
1543
1544    std::string id;
1545
1546    typedef std::map<std::string, Item*> ItemReaders;
1547    ItemReaders readers;
1548    std::auto_ptr<IdReaderBase<Item> > idReader;
1549  };
1550
1551  /// \ingroup io_group
1552  /// \brief SectionReader for attributes.
1553  ///
1554  /// The lemon format can store multiple attribute set. Each set has
1555  /// the header line \c \@attributes \c attributeset_id, but the
1556  /// attributeset_id may be empty.
1557  ///
1558  /// The attributeset section contains several lines. Each of them starts
1559  /// with an attribute and then a the value for the id.
1560  ///
1561  /// \relates LemonReader
1562  template <typename _Traits = DefaultReaderTraits>
1563  class AttributeReader : public CommonSectionReaderBase {
1564    typedef CommonSectionReaderBase Parent;
1565    typedef _Traits Traits;
1566  public:
1567    /// \brief Constructor.
1568    ///
1569    /// Constructor for AttributeReader. It creates the AttributeReader and
1570    /// attach it into the given LemonReader. The reader process a section
1571    /// only if the \c section_id and the \c _id are the same.
1572    AttributeReader(LemonReader& _reader,
1573                    const std::string& _id = std::string())
1574      : Parent(_reader), id(_id) {}
1575
1576    /// \brief Destructor.
1577    ///
1578    /// Destructor for AttributeReader.
1579    virtual ~AttributeReader() {
1580      for (typename Readers::iterator it = readers.begin();
1581           it != readers.end(); ++it) {
1582        delete it->second;
1583      }
1584    }
1585
1586  private:
1587    AttributeReader(const AttributeReader&);
1588    void operator=(AttributeReader&);
1589
1590  public:
1591    /// \brief Add an attribute reader command for the reader.
1592    ///
1593    /// Add an attribute reader command for the reader.
1594    template <typename Value>
1595    AttributeReader& readAttribute(const std::string& id, Value& value) {
1596      return readAttribute<typename Traits::template Reader<Value> >
1597        (id, value);
1598    }
1599
1600    /// \brief Add an attribute reader command for the reader.
1601    ///
1602    /// Add an attribute reader command for the reader.
1603    template <typename Reader, typename Value>
1604    AttributeReader& readAttribute(const std::string& name, Value& value,
1605                                   const Reader& reader = Reader()) {
1606      if (readers.find(name) != readers.end()) {
1607        ErrorMessage msg;
1608        msg << "Multiple read rule for attribute: " << name;
1609        throw IOParameterError(msg.message());
1610      }
1611      readers.insert(make_pair(name, new ValueReader<Value, Reader>
1612                               (value, reader)));
1613      return *this;
1614    }
1615
1616  protected:
1617
1618    /// \brief Gives back true when the SectionReader can process
1619    /// the section with the given header line.
1620    ///
1621    /// It gives back true when the header line start with \c \@attributes,
1622    /// and the header line's id and the attributeset's id are the same.
1623    bool header(const std::string& line) {
1624      std::istringstream ls(line);
1625      std::string command;
1626      std::string name;
1627      ls >> command >> name;
1628      return command == "@attributes" && name == id;
1629    }
1630
1631    /// \brief Reader function of the section.
1632    ///
1633    /// It reads the content of the section.
1634    void read(std::istream& is) {
1635      std::string line;
1636      while (getline(is, line)) {
1637        std::istringstream ls(line);
1638        std::string id;
1639        ls >> id;
1640        typename Readers::iterator it = readers.find(id);
1641        if (it != readers.end()) {
1642          it->second->read(ls);
1643        }
1644      }
1645    }   
1646
1647  private:
1648    std::string id;
1649
1650    typedef std::map<std::string, ValueReaderBase*> Readers;
1651    Readers readers; 
1652  };
1653
1654}
1655#endif
Note: See TracBrowser for help on using the repository browser.