COIN-OR::LEMON - Graph Library

source: lemon-0.x/lemon/lemon_reader.h @ 1845:f8bbfed86036

Last change on this file since 1845:f8bbfed86036 was 1845:f8bbfed86036, checked in by Balazs Dezso, 14 years ago

Implementation redesign
Throws exception

File size: 66.5 KB
Line 
1/* -*- C++ -*-
2 * 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#include <lemon/xy.h>
40
41#include <lemon/concept_check.h>
42#include <lemon/concept/maps.h>
43
44namespace lemon {
45
46  namespace _reader_bits {
47
48    template <typename T>
49    bool operator<(T, T) {
50      throw DataFormatError("Id is not comparable");
51    }
52
53    template <typename T>
54    struct Less {
55      bool operator()(const T& p, const T& q) const {
56        return p < q;
57      }
58    };
59
60    template <typename Item>
61    class ItemIdReader {
62    public:
63
64      bool isIdReader() { return true; }
65
66      void readId(std::istream&, Item&) {}
67     
68      template <class _ItemIdReader>
69      struct Constraints {
70        void constraints() {
71          bool b = reader.isIdReader();
72          ignore_unused_variable_warning(b);
73          Item item;
74          reader.readId(is, item);
75        }
76        _ItemIdReader& reader;
77        std::istream& is;
78      };
79
80    };
81
82    template <typename Item>
83    class ItemReader {
84    public:
85      void read(std::istream&, Item&) {}
86     
87      template <class _ItemReader>
88      struct Constraints {
89        void constraints() {
90          Item item;
91          reader.read(is, item);
92        }
93        _ItemReader& reader;
94        std::istream& is;
95      };
96
97    };
98
99    template <typename Map>
100    struct Ref { typedef Map& Type; };
101    template <typename Map>
102    struct Arg { typedef Map& Type; };
103
104    template <typename Graph, typename Map>
105    class ForwardComposeMap {
106    public:
107      typedef typename Graph::UndirEdge Key;
108      typedef typename Map::Value Value;
109
110      ForwardComposeMap(const Graph& _graph, typename Arg<Map>::Type _map)
111        : graph(_graph), map(_map) {}
112     
113      void set(const Key& key, const Value& val) {
114        map.set(graph.direct(key, true), val);
115      }
116
117    private:
118      typename Ref<Map>::Type map;
119      const Graph& graph;
120    };
121
122    template <typename Graph, typename Map>
123    ForwardComposeMap<Graph, Map>
124    forwardComposeMap(const Graph& graph, const Map& map) {
125      return ForwardComposeMap<Graph, Map>(graph, map);
126    }
127
128    template <typename Graph, typename Map>
129    ForwardComposeMap<Graph, Map>
130    forwardComposeMap(const Graph& graph, Map& map) {
131      return ForwardComposeMap<Graph, Map>(graph, map);
132    }
133
134    template <typename Graph, typename Map>
135    class BackwardComposeMap {
136    public:
137      typedef typename Graph::UndirEdge Key;
138      typedef typename Map::Value Value;
139
140      BackwardComposeMap(const Graph& _graph, typename Arg<Map>::Type _map)
141        : graph(_graph), map(_map) {}
142     
143      void set(const Key& key, const Value& val) {
144        map.set(graph.direct(key, false), val);
145      }
146
147    private:
148      typename Ref<Map>::Type map;
149      const Graph& graph;
150    };
151
152
153    template <typename Graph, typename Map>
154    BackwardComposeMap<Graph, Map>
155    backwardComposeMap(const Graph& graph, const Map& map) {
156      return BackwardComposeMap<Graph, Map>(graph, map);
157    }
158
159    template <typename Graph, typename Map>
160    BackwardComposeMap<Graph, Map>
161    backwardComposeMap(const Graph& graph, Map& map) {
162      return BackwardComposeMap<Graph, Map>(graph, map);
163    }
164
165    template <typename Graph, typename Map>
166    struct Ref<ForwardComposeMap<Graph, Map> > {
167      typedef ForwardComposeMap<Graph, Map> Type;
168    };
169    template <typename Graph, typename Map>
170    struct Arg<ForwardComposeMap<Graph, Map> > {
171      typedef const ForwardComposeMap<Graph, Map>& Type;
172    };
173
174    template <typename Graph, typename Map>
175    struct Ref<BackwardComposeMap<Graph, Map> > {
176      typedef BackwardComposeMap<Graph, Map> Type;
177    };
178    template <typename Graph, typename Map>
179    struct Arg<BackwardComposeMap<Graph, Map> > {
180      typedef const BackwardComposeMap<Graph, Map>& Type;
181    };
182
183    template <typename Map>
184    struct Ref<XMap<Map> > {
185      typedef XMap<Map> Type;
186    };
187    template <typename Map>
188    struct Arg<XMap<Map> > {
189      typedef const XMap<Map>& Type;
190    };
191
192    template <typename Map>
193    struct Ref<YMap<Map> > {
194      typedef YMap<Map> Type;
195    };
196    template <typename Map>
197    struct Arg<YMap<Map> > {
198      typedef const YMap<Map>& Type;
199    };
200
201
202    template <typename _Item>
203    class MapReaderBase;
204   
205    template <typename _Item>
206    class MapInverterBase : public MapReaderBase<_Item> {
207    public:
208      typedef _Item Item;
209      virtual void read(std::istream&, const Item&) = 0;
210      virtual Item read(std::istream&) const = 0;
211
212      virtual MapInverterBase<_Item>* getInverter() {
213        return this;
214      }
215    };
216
217    template <typename _Item, typename _Map, typename _Reader>
218    class MapReaderInverter : public MapInverterBase<_Item> {
219    public:
220      typedef _Item Item;
221      typedef _Reader Reader;
222      typedef typename Reader::Value Value;
223      typedef _Map Map;
224      typedef std::map<Value, Item, _reader_bits::Less<Value> > Inverse;
225
226      typename _reader_bits::Ref<Map>::Type map;
227      Reader reader;
228      Inverse inverse;
229
230      MapReaderInverter(typename _reader_bits::Arg<Map>::Type _map,
231                        const Reader& _reader)
232        : map(_map), reader(_reader) {}
233
234      virtual ~MapReaderInverter() {}
235
236      virtual void read(std::istream& is, const Item& item) {
237        Value value;
238        reader.read(is, value);
239        map.set(item, value);
240        typename Inverse::iterator it = inverse.find(value);
241        if (it == inverse.end()) {
242          inverse.insert(std::make_pair(value, item));
243        } else {
244          throw DataFormatError("Multiple ID occurence");
245        }
246      }
247
248      virtual Item read(std::istream& is) const {
249        Value value;
250        reader.read(is, value);
251        typename Inverse::const_iterator it = inverse.find(value);
252        if (it != inverse.end()) {
253          return it->second;
254        } else {
255          throw DataFormatError("Invalid ID error");
256        }
257      }     
258    };
259
260    template <typename _Item, typename _Reader>
261    class SkipReaderInverter : public MapInverterBase<_Item> {
262    public:
263      typedef _Item Item;
264      typedef _Reader Reader;
265      typedef typename Reader::Value Value;
266      typedef std::map<Value, Item, _reader_bits::Less<Value> > Inverse;
267
268      Reader reader;
269
270      SkipReaderInverter(const Reader& _reader)
271        : reader(_reader) {}
272
273      virtual ~SkipReaderInverter() {}
274
275      virtual void read(std::istream& is, const Item& item) {
276        Value value;
277        reader.read(is, value);
278        typename Inverse::iterator it = inverse.find(value);
279        if (it == inverse.end()) {
280          inverse.insert(std::make_pair(value, item));
281        } else {
282          throw DataFormatError("Multiple ID occurence error");
283        }
284      }
285
286      virtual Item read(std::istream& is) const {
287        Value value;
288        reader.read(is, value);
289        typename Inverse::const_iterator it = inverse.find(value);
290        if (it != inverse.end()) {
291          return it->second;
292        } else {
293          throw DataFormatError("Invalid ID error");
294        }
295      }
296
297    private:
298      Inverse inverse;
299    };
300
301    template <typename _Item>   
302    class MapReaderBase {
303    public:
304      typedef _Item Item;
305
306      MapReaderBase() { _touched = false; }
307     
308      void touch() { _touched = true; }
309      bool touched() const { return _touched; }
310
311      virtual ~MapReaderBase() {}
312
313      virtual void read(std::istream& is, const Item& item) = 0;
314      virtual MapInverterBase<_Item>* getInverter() = 0;
315
316    private:     
317      bool _touched;
318
319    };
320
321    template <typename _Item, typename _Map, typename _Reader>
322    class MapReader : public MapReaderBase<_Item> {
323    public:
324      typedef _Map Map;
325      typedef _Reader Reader;
326      typedef typename Reader::Value Value;
327      typedef _Item Item;
328     
329      typename _reader_bits::Ref<Map>::Type map;
330      Reader reader;
331
332      MapReader(typename _reader_bits::Arg<Map>::Type _map,
333                const Reader& _reader)
334        : map(_map), reader(_reader) {}
335
336      virtual ~MapReader() {}
337
338      virtual void read(std::istream& is, const Item& item) {
339        Value value;
340        reader.read(is, value);
341        map.set(item, value);
342      }
343
344      virtual MapInverterBase<_Item>* getInverter() {
345        return new MapReaderInverter<Item, Map, Reader>(map, reader);
346      }
347    };
348
349
350    template <typename _Item, typename _Reader>
351    class SkipReader : public MapReaderBase<_Item> {
352    public:
353      typedef _Reader Reader;
354      typedef typename Reader::Value Value;
355      typedef _Item Item;
356
357      Reader reader;
358      SkipReader(const Reader& _reader) : reader(_reader) {}
359
360      virtual ~SkipReader() {}
361
362      virtual void read(std::istream& is, const Item&) {
363        Value value;
364        reader.read(is, value);
365      }     
366
367      virtual MapInverterBase<Item>* getInverter() {
368        return new SkipReaderInverter<Item, Reader>(reader);
369      }
370    };
371
372    template <typename _Item>
373    class IdReaderBase {
374    public:
375      typedef _Item Item;
376      virtual ~IdReaderBase() {}
377      virtual Item read(std::istream& is) const = 0;
378      virtual bool isIdReader() const = 0;
379    };
380
381    template <typename _Item, typename _BoxedIdReader>
382    class IdReader : public IdReaderBase<_Item> {
383    public:
384      typedef _Item Item;
385      typedef _BoxedIdReader BoxedIdReader;
386     
387      const BoxedIdReader& boxedIdReader;
388
389      IdReader(const BoxedIdReader& _boxedIdReader)
390        : boxedIdReader(_boxedIdReader) {}
391
392      virtual Item read(std::istream& is) const {
393        Item item;
394        boxedIdReader.readId(is, item);
395        return item;
396      }
397
398      virtual bool isIdReader() const {
399        return boxedIdReader.isIdReader();
400      }
401    };
402
403    template <typename _Item>
404    class ItemStore {
405    public:
406
407      typedef _Item Item;
408
409      ItemStore(Item& _item) : item(&_item) {
410        _touched = false;
411      }
412     
413      void touch() { _touched = true; }
414      bool touched() const { return _touched; }
415
416      void read(const Item& _item) {
417        *item = _item;
418      }
419     
420    private:
421      Item* item;
422      bool _touched;
423    };
424
425    class ValueReaderBase {
426    public:
427      virtual void read(std::istream&) {};
428      virtual ~ValueReaderBase() {}
429    };
430
431    template <typename _Value, typename _Reader>
432    class ValueReader : public ValueReaderBase {
433    public:
434      typedef _Value Value;
435      typedef _Reader Reader;
436
437      ValueReader(Value& _value, const Reader& _reader)
438        : value(_value), reader(_reader) {}
439
440      virtual void read(std::istream& is) {
441        reader.read(is, value);
442      }
443    private:
444      Value& value;
445      Reader reader;
446    };
447
448  }
449
450  /// \ingroup io_group
451  /// \brief Lemon Format reader class.
452  ///
453  /// The Lemon Format contains several sections. We do not want to
454  /// determine what sections are in a lemon file we give only a framework
455  /// to read a section oriented format.
456  ///
457  /// In the Lemon Format each section starts with a line contains a \c \@
458  /// character on the first not white space position. This line is the
459  /// header line of the section. Each next lines belong to this section
460  /// while it does not starts with \c \@ character. This line can start a
461  /// new section or if it can close the file with the \c \@end line.
462  /// The file format ignore the empty and comment lines. The line is
463  /// comment line if it starts with a \c # character.
464  ///
465  /// The framework provides an abstract LemonReader::SectionReader class
466  /// what defines the interface of a SectionReader. The SectionReader
467  /// has the \c header() member function what get a header line string and
468  /// decides if it want to process the next section. Several SectionReaders
469  /// can be attached to an LemonReader and the first attached what can
470  /// process the section will be used. Its \c read() member will called
471  /// with a stream contains the section. From this stream the empty and
472  /// comment lines are filtered out.
473  ///
474  /// \relates GraphReader
475  /// \relates NodeSetReader
476  /// \relates EdgeSetReader
477  /// \relates NodesReader
478  /// \relates EdgesReader
479  /// \relates AttributeReader
480  class LemonReader {
481  private:
482   
483    class FilterStreamBuf : public std::streambuf {
484    public:
485
486      typedef std::streambuf Parent;
487      typedef Parent::char_type char_type;
488      FilterStreamBuf(std::istream& is, int& num)
489        : _is(is), _base(0), _eptr(0),
490          _num(num), skip_state(after_endl) {}
491
492    protected:
493
494      enum skip_state_type {
495        no_skip,
496        after_endl,
497        comment_line
498      };
499
500      char_type small_buf[1];
501
502
503      std::istream& _is;
504
505      char_type* _base;
506      char_type* _eptr;
507
508      int& _num;
509
510      skip_state_type skip_state;
511
512
513      char_type* base() { return _base; }
514
515      char_type* eptr() { return _eptr; }
516
517      int blen() { return _eptr - _base; }
518
519      void setb(char_type* buf, int len) {
520        _base = buf;
521        _eptr = buf + len;
522      }
523 
524      virtual std::streambuf* setbuf(char *buf, std::streamsize len) {
525        if (base()) return 0;
526        if (buf != 0 && len >= (int)sizeof(small_buf)) {
527          setb(buf, len);
528        } else {
529          setb(small_buf, sizeof(small_buf));
530        }
531        setg(0, 0, 0);
532        return this;
533      }
534
535      bool put_char(char c) {
536        switch (skip_state) {
537        case no_skip:
538          switch (c) {
539          case '\n':
540            skip_state = after_endl;
541            return true;
542          default:
543            return true;
544          }
545        case after_endl:
546          switch (c) {
547          case '@':
548            return false;
549          case '\n':
550            return false;
551          case '#':
552            skip_state = comment_line;
553            return false;
554          default:
555            if (!isspace(c)) {
556              skip_state = no_skip;
557              return true;
558            } else {
559              return false;
560            }
561          }
562          break;
563        case comment_line:
564          switch (c) {
565          case '\n':
566            skip_state = after_endl;
567            return false;
568          default:
569            return false;
570          }
571        }
572        return false;
573      }
574
575      virtual int underflow() {
576        char c;
577        if (_is.read(&c, 1)) {
578          _is.putback(c);
579          if (c == '@') {
580            return EOF;
581          }
582        } else {
583          return EOF;
584        }
585        char_type *ptr;
586        for (ptr = base(); ptr != eptr(); ++ptr) {
587          if (_is.read(&c, 1)) {
588            if (c == '\n') ++_num;
589            if (put_char(c)) {
590              *ptr = c;
591            } else {
592              if (skip_state == after_endl && c == '@') {
593                _is.putback('@');
594                break;
595              }
596              --ptr;
597            }
598          } else {
599            break;
600          }
601        }
602        setg(base(), base(), ptr);
603        return *base();
604      }
605
606      virtual int sync() {
607        return EOF;
608      }
609    };
610
611  public:
612
613    /// \brief Abstract base class for reading a section.
614    ///
615    /// This class has an \c header() member function what get a
616    /// header line string and decides if it want to process the next
617    /// section. Several SectionReaders can be attached to an LemonReader
618    /// and the first attached what can process the section will be used.
619    /// Its \c read() member will called with a stream contains the section.
620    /// From this stream the empty lines and comments are filtered out.
621    class SectionReader {
622      friend class LemonReader;
623    protected:
624      /// \brief Constructor for SectionReader.
625      ///
626      /// Constructor for SectionReader. It attach this reader to
627      /// the given LemonReader.
628      SectionReader(LemonReader& reader) {
629        reader.attach(*this);
630      }
631
632      virtual ~SectionReader() {}
633
634      /// \brief Gives back true when the SectionReader can process
635      /// the section with the given header line.
636      ///
637      /// It gives back true when the SectionReader can process
638      /// the section with the given header line.
639      virtual bool header(const std::string& line) = 0;
640
641      /// \brief Reader function of the section.
642      ///
643      /// It reads the content of the section.
644      virtual void read(std::istream& is) = 0;
645    };
646
647    /// \brief Constructor for LemonReader.
648    ///
649    /// Constructor for LemonReader which reads from the given stream.
650    LemonReader(std::istream& _is)
651      : is(&_is), own_is(false) {}
652
653    /// \brief Constructor for LemonReader.
654    ///
655    /// Constructor for LemonReader which reads from the given file.
656    LemonReader(const std::string& filename)
657      : is(0), own_is(true) {
658      is = new std::ifstream(filename.c_str());
659      if (is->fail()) {
660        throw FileOpenError(filename);
661      }
662    }
663
664    /// \brief Desctructor for LemonReader.
665    ///
666    /// Desctructor for LemonReader.
667    ~LemonReader() {
668      if (own_is) {
669        delete is;
670      }
671    }
672
673  private:
674    LemonReader(const LemonReader&);
675    void operator=(const LemonReader&);
676
677    void attach(SectionReader& reader) {
678      readers.push_back(&reader);
679    }
680
681  public:
682    /// \brief Executes the LemonReader.
683    ///
684    /// It executes the LemonReader.
685    void run() {
686      int line_num = 0;
687      std::string line;
688      try {
689        while ((++line_num, getline(*is, line)) && line.find("@end") != 0) {
690          SectionReaders::iterator it;
691          for (it = readers.begin(); it != readers.end(); ++it) {
692            if ((*it)->header(line)) {
693              char buf[2048];
694              FilterStreamBuf buffer(*is, line_num);
695              buffer.pubsetbuf(buf, sizeof(buf));
696              std::istream is(&buffer);
697              (*it)->read(is);
698              break;
699            }
700          }
701        }
702      } catch (DataFormatError& error) {
703        error.line(line_num);
704        throw error;
705      }
706    }
707
708
709  private:
710
711    std::istream* is;
712    bool own_is;
713
714    typedef std::vector<SectionReader*> SectionReaders;
715    SectionReaders readers;
716
717  };
718
719  /// \ingroup io_group
720  /// \brief SectionReader for reading a graph's nodeset.
721  ///
722  /// The lemon format can store multiple graph nodesets with several maps.
723  /// The nodeset section's header line is \c \@nodeset \c nodeset_id, but the
724  /// \c nodeset_id may be empty.
725  ///
726  /// The first line of the section contains the names of the maps separated
727  /// with white spaces. Each next lines describes a node in the nodeset, and
728  /// contains the mapped values for each map.
729  ///
730  /// If the nodeset contains an \c "id" named map then it will be regarded
731  /// as id map. This map should contain only unique values and when the
732  /// \c readId() member will read a value from the given stream it will
733  /// give back that node which is mapped to this value.
734  ///
735  /// \relates LemonReader
736  template <typename _Graph, typename _Traits = DefaultReaderTraits>
737  class NodeSetReader : public LemonReader::SectionReader {
738    typedef LemonReader::SectionReader Parent;
739  public:
740
741    typedef _Graph Graph;
742    typedef _Traits Traits;
743    typedef typename Graph::Node Node;
744    typedef typename Traits::Skipper DefaultSkipper;
745
746    /// \brief Constructor.
747    ///
748    /// Constructor for NodeSetReader. It creates the NodeSetReader and
749    /// attach it into the given LemonReader. The nodeset reader will
750    /// add the readed nodes to the given Graph. The reader will read
751    /// the section when the \c section_id and the \c _id are the same.
752    NodeSetReader(LemonReader& _reader,
753                  Graph& _graph,
754                  const std::string& _id = std::string(),
755                  const DefaultSkipper& _skipper = DefaultSkipper())
756      : Parent(_reader), graph(_graph), id(_id), skipper(_skipper) {}
757
758
759    /// \brief Destructor.
760    ///
761    /// Destructor for NodeSetReader.
762    virtual ~NodeSetReader() {
763      for (typename MapReaders::iterator it = readers.begin();
764           it != readers.end(); ++it) {
765        delete it->second;
766      }
767    }
768
769  private:
770    NodeSetReader(const NodeSetReader&);
771    void operator=(const NodeSetReader&);
772 
773  public:
774
775    /// \brief Add a new node map reader command for the reader.
776    ///
777    /// Add a new node map reader command for the reader.
778    template <typename Map>
779    NodeSetReader& readNodeMap(std::string name, Map& map) {
780      return _readMap<
781        typename Traits::template Reader<typename Map::Value>, Map,
782        typename _reader_bits::Arg<Map>::Type>(name, map);
783    }
784
785    template <typename Map>
786    NodeSetReader& readNodeMap(std::string name, const Map& map) {
787      return _readMap<
788        typename Traits::template Reader<typename Map::Value>, Map,
789        typename _reader_bits::Arg<Map>::Type>(name, map);
790    }
791
792    /// \brief Add a new node map reader command for the reader.
793    ///
794    /// Add a new node map reader command for the reader.
795    template <typename Reader, typename Map>
796    NodeSetReader& readNodeMap(std::string name, Map& map,
797                               const Reader& reader = Reader()) {
798      return _readMap<Reader, Map, typename _reader_bits::Arg<Map>::Type>
799        (name, map, reader);
800    }
801
802    template <typename Reader, typename Map>
803    NodeSetReader& readNodeMap(std::string name, const Map& map,
804                               const Reader& reader = Reader()) {
805      return _readMap<Reader, Map, typename _reader_bits::Arg<Map>::Type>
806        (name, map, reader);
807    }
808
809  private:
810
811    template <typename Reader, typename Map, typename MapParameter>
812    NodeSetReader& _readMap(std::string name, MapParameter map,
813                            const Reader& reader = Reader()) {
814      checkConcept<concept::WriteMap<Node, typename Map::Value>, Map>();
815      checkConcept<_reader_bits::ItemReader<typename Map::Value>, Reader>();
816      if (readers.find(name) != readers.end()) {
817        ErrorMessage msg;
818        msg << "Multiple read rule for node map: " << name;
819        throw IOParameterError(msg.message());
820      }     
821      readers.insert(
822        make_pair(name, new _reader_bits::
823                  MapReader<Node, Map, Reader>(map, reader)));
824      return *this;
825    }
826
827  public:
828
829    /// \brief Add a new node map skipper command for the reader.
830    ///
831    /// Add a new node map skipper command for the reader.
832    template <typename Reader>
833    NodeSetReader& skipNodeMap(std::string name,
834                           const Reader& reader = Reader()) {
835      if (readers.find(name) != readers.end()) {
836        ErrorMessage msg;
837        msg << "Multiple read rule for node map: " << name;
838        throw IOParameterError(msg.message());
839      }
840      readers.insert(make_pair(name, new _reader_bits::
841                               SkipReader<Node, Reader>(reader)));
842      return *this;
843    }
844
845  protected:
846
847    /// \brief Gives back true when the SectionReader can process
848    /// the section with the given header line.
849    ///
850    /// It gives back true when the header line starts with \c \@nodeset,
851    /// and the header line's id and the nodeset's id are the same.
852    virtual bool header(const std::string& line) {
853      std::istringstream ls(line);
854      std::string command;
855      std::string name;
856      ls >> command >> name;
857      return command == "@nodeset" && name == id;
858    }
859
860    /// \brief Reader function of the section.
861    ///
862    /// It reads the content of the section.
863    virtual void read(std::istream& is) {
864      std::vector<_reader_bits::MapReaderBase<Node>* > index;
865      std::string line;
866
867      getline(is, line);
868      std::istringstream ls(line);     
869      while (ls >> id) {
870        typename MapReaders::iterator it = readers.find(id);
871        if (it != readers.end()) {
872          it->second->touch();
873          index.push_back(it->second);
874        } else {
875          index.push_back(&skipper);
876        }
877        if (id == "id" && inverter.get() == 0) {
878          inverter.reset(index.back()->getInverter());
879          index.back() = inverter.get();
880        }
881      }
882      for (typename MapReaders::iterator it = readers.begin();
883           it != readers.end(); ++it) {
884        if (!it->second->touched()) {
885          ErrorMessage msg;
886          msg << "Map not found in file: " << it->first;
887          throw IOParameterError(msg.message());
888        }
889      }
890      while (getline(is, line)) {       
891        Node node = graph.addNode();
892        std::istringstream ls(line);
893        for (int i = 0; i < (int)index.size(); ++i) {
894          index[i]->read(ls, node);
895        }
896      }
897    }
898
899  public:
900
901    /// \brief Returns true if the nodeset can give back the node by its id.
902    ///
903    /// Returns true if the nodeset can give back the node by its id.
904    /// It is possible only if an "id" named map was read.
905    bool isIdReader() const {
906      return inverter.get() != 0;
907    }
908
909    /// \brief Gives back the node by its id.
910    ///
911    /// It reads an id from the stream and gives back which node belongs to
912    /// it. It is possible only if there was read an "id" named map.
913    void readId(std::istream& is, Node& node) const {
914      node = inverter->read(is);
915    }
916
917  private:
918
919    typedef std::map<std::string, _reader_bits::MapReaderBase<Node>*> MapReaders;
920    MapReaders readers;
921   
922    Graph& graph;   
923    std::string id;
924    _reader_bits::SkipReader<Node, DefaultSkipper> skipper;
925
926    std::auto_ptr<_reader_bits::MapInverterBase<Node> > inverter;
927  };
928
929  /// \ingroup io_group
930  /// \brief SectionReader for reading a graph's edgeset.
931  ///
932  /// The lemon format can store multiple graph edgesets with several maps.
933  /// The edgeset section's header line is \c \@edgeset \c edgeset_id, but the
934  /// \c edgeset_id may be empty.
935  ///
936  /// The first line of the section contains the names of the maps separated
937  /// with white spaces. Each next lines describes an edge in the edgeset. The
938  /// line contains the source and the target nodes' id and the mapped
939  /// values for each map.
940  ///
941  /// If the edgeset contains an \c "id" named map then it will be regarded
942  /// as id map. This map should contain only unique values and when the
943  /// \c readId() member will read a value from the given stream it will
944  /// give back that edge which is mapped to this value.
945  ///
946  /// The edgeset reader needs a node id reader to identify which nodes
947  /// have to be connected. If a NodeSetReader reads an "id" named map,
948  /// it will be able to resolve the nodes by ids.
949  ///
950  /// \relates LemonReader
951  template <typename _Graph, typename _Traits = DefaultReaderTraits>
952  class EdgeSetReader : public LemonReader::SectionReader {
953    typedef LemonReader::SectionReader Parent;
954  public:
955
956    typedef _Graph Graph;
957    typedef _Traits Traits;
958    typedef typename Graph::Node Node;
959    typedef typename Graph::Edge Edge;
960    typedef typename Traits::Skipper DefaultSkipper;
961
962    /// \brief Constructor.
963    ///
964    /// Constructor for EdgeSetReader. It creates the EdgeSetReader and
965    /// attach it into the given LemonReader. The edgeset reader will
966    /// add the readed edges to the given Graph. It will use the given
967    /// node id reader to read the source and target nodes of the edges.
968    /// The reader will read the section only if the \c _id and the
969    /// \c edgset_id are the same.
970    template <typename NodeIdReader>
971    EdgeSetReader(LemonReader& _reader,
972                  Graph& _graph,
973                  const NodeIdReader& _nodeIdReader,
974                  const std::string& _id = std::string(),
975                  const DefaultSkipper& _skipper = DefaultSkipper())
976      : Parent(_reader), graph(_graph), id(_id), skipper(_skipper) {
977      checkConcept<_reader_bits::ItemIdReader<Node>, NodeIdReader>();
978      nodeIdReader.reset(new _reader_bits::
979                         IdReader<Node, NodeIdReader>(_nodeIdReader));
980    }
981    /// \brief Destructor.
982    ///
983    /// Destructor for EdgeSetReader.
984    virtual ~EdgeSetReader() {
985      for (typename MapReaders::iterator it = readers.begin();
986           it != readers.end(); ++it) {
987        delete it->second;
988      }
989    }
990
991  private:
992    EdgeSetReader(const EdgeSetReader&);
993    void operator=(const EdgeSetReader&);
994
995  public:
996
997    /// \brief Add a new edge map reader command for the reader.
998    ///
999    /// Add a new edge map reader command for the reader.
1000    template <typename Map>
1001    EdgeSetReader& readEdgeMap(std::string name, Map& map) {
1002      return _readMap<
1003        typename Traits::template Reader<typename Map::Value>, Map,
1004        typename _reader_bits::Arg<Map>::Type>(name, map);
1005    }
1006
1007    template <typename Map>
1008    EdgeSetReader& readEdgeMap(std::string name, const Map& map) {
1009      return _readMap<
1010        typename Traits::template Reader<typename Map::Value>, Map,
1011        typename _reader_bits::Arg<Map>::Type>(name, map);
1012    }
1013
1014    /// \brief Add a new edge map reader command for the reader.
1015    ///
1016    /// Add a new edge map reader command for the reader.
1017    template <typename Reader, typename Map>
1018    EdgeSetReader& readEdgeMap(std::string name, Map& map,
1019                           const Reader& reader = Reader()) {
1020      return _readMap<Reader, Map,
1021        typename _reader_bits::Arg<Map>::Type>(name, map, reader);
1022    }
1023
1024    template <typename Reader, typename Map>
1025    EdgeSetReader& readEdgeMap(std::string name, const Map& map,
1026                               const Reader& reader = Reader()) {
1027      return _readMap<Reader, Map,
1028        typename _reader_bits::Arg<Map>::Type>(name, map, reader);
1029    }
1030
1031  private:
1032
1033    template <typename Reader, typename Map, typename MapParameter>
1034    EdgeSetReader& _readMap(std::string name, MapParameter map,
1035                            const Reader& reader = Reader()) {
1036      checkConcept<concept::WriteMap<Edge, typename Map::Value>, Map>();
1037      checkConcept<_reader_bits::ItemReader<typename Map::Value>, Reader>();
1038      if (readers.find(name) != readers.end()) {
1039        ErrorMessage msg;
1040        msg << "Multiple read rule for edge map: " << name;
1041        throw IOParameterError(msg.message());
1042      }
1043      readers.insert(
1044        make_pair(name, new _reader_bits::
1045                  MapReader<Edge, Map, Reader>(map, reader)));
1046      return *this;
1047    }
1048
1049  public:
1050
1051    /// \brief Add a new edge map skipper command for the reader.
1052    ///
1053    /// Add a new edge map skipper command for the reader.
1054    template <typename Reader>
1055    EdgeSetReader& skipEdgeMap(std::string name,
1056                               const Reader& reader = Reader()) {
1057      if (readers.find(name) != readers.end()) {
1058        ErrorMessage msg;
1059        msg << "Multiple read rule for edge map: " << name;
1060        throw IOParameterError(msg.message());
1061      }
1062      readers.insert(make_pair(name, new _reader_bits::
1063                               SkipReader<Edge, Reader>(reader)));
1064      return *this;
1065    }
1066
1067  protected:
1068
1069    /// \brief Gives back true when the SectionReader can process
1070    /// the section with the given header line.
1071    ///
1072    /// It gives back true when the header line starts with \c \@edgeset,
1073    /// and the header line's id and the edgeset's id are the same.
1074    virtual bool header(const std::string& line) {
1075      std::istringstream ls(line);
1076      std::string command;
1077      std::string name;
1078      ls >> command >> name;
1079      return command == "@edgeset" && name == id;
1080    }
1081
1082    /// \brief Reader function of the section.
1083    ///
1084    /// It reads the content of the section.
1085    virtual void read(std::istream& is) {
1086      if (!nodeIdReader->isIdReader()) {
1087        throw DataFormatError("Cannot find nodeset or ID map");
1088      }
1089      std::vector<_reader_bits::MapReaderBase<Edge>* > index;
1090      std::string line;
1091
1092      getline(is, line);
1093      std::istringstream ls(line);     
1094      while (ls >> id) {
1095        typename MapReaders::iterator it = readers.find(id);
1096        if (it != readers.end()) {
1097          index.push_back(it->second);
1098          it->second->touch();
1099        } else {
1100          index.push_back(&skipper);
1101        }
1102        if (id == "id" && inverter.get() == 0) {
1103          inverter.reset(index.back()->getInverter());
1104          index.back() = inverter.get();
1105        }
1106      }
1107      for (typename MapReaders::iterator it = readers.begin();
1108           it != readers.end(); ++it) {
1109        if (!it->second->touched()) {
1110          ErrorMessage msg;
1111          msg << "Map not found in file: " << it->first;
1112          throw IOParameterError(msg.message());
1113        }
1114      }
1115      while (getline(is, line)) {       
1116        std::istringstream ls(line);
1117        Node from = nodeIdReader->read(ls);
1118        Node to = nodeIdReader->read(ls);
1119        Edge edge = graph.addEdge(from, to);
1120        for (int i = 0; i < (int)index.size(); ++i) {
1121          index[i]->read(ls, edge);
1122        }
1123      }
1124    }
1125
1126  public:
1127
1128    /// \brief Returns true if the edgeset can give back the edge by its id.
1129    ///
1130    /// Returns true if the edgeset can give back the edge by its id.
1131    /// It is possible only if an "id" named map was read.
1132    bool isIdReader() const {
1133      return inverter.get() != 0;
1134    }
1135
1136    /// \brief Gives back the edge by its id.
1137    ///
1138    /// It reads an id from the stream and gives back which edge belongs to
1139    /// it. It is possible only if there was read an "id" named map.
1140    void readId(std::istream& is, Edge& edge) const {
1141      edge = inverter->read(is);
1142    }
1143
1144  private:
1145
1146    typedef std::map<std::string, _reader_bits::MapReaderBase<Edge>*> MapReaders;
1147    MapReaders readers;
1148   
1149    Graph& graph;   
1150    std::string id;
1151    _reader_bits::SkipReader<Edge, DefaultSkipper> skipper;
1152
1153    std::auto_ptr<_reader_bits::MapInverterBase<Edge> > inverter;
1154    std::auto_ptr<_reader_bits::IdReaderBase<Node> > nodeIdReader;
1155  };
1156
1157  /// \ingroup io_group
1158  /// \brief SectionReader for reading a undirected graph's edgeset.
1159  ///
1160  /// The lemon format can store multiple undirected edgesets with several
1161  /// maps. The undirected edgeset section's header line is \c \@undiredgeset
1162  /// \c undiredgeset_id, but the \c undiredgeset_id may be empty.
1163  ///
1164  /// The first line of the section contains the names of the maps separated
1165  /// with white spaces. Each next lines describes an edge in the edgeset. The
1166  /// line contains the connected nodes' id and the mapped values for each map.
1167  ///
1168  /// The section can handle the directed as a syntactical sugar. Two
1169  /// undirected edge map describes one directed edge map. This two maps
1170  /// are the forward map and the backward map and the names of this map
1171  /// is near the same just with a prefix \c '+' or \c '-' character
1172  /// difference.
1173  ///
1174  /// If the edgeset contains an \c "id" named map then it will be regarded
1175  /// as id map. This map should contain only unique values and when the
1176  /// \c readId() member will read a value from the given stream it will
1177  /// give back that undiricted edge which is mapped to this value.
1178  ///
1179  /// The undirected edgeset reader needs a node id reader to identify which
1180  /// nodes have to be connected. If a NodeSetReader reads an "id" named map,
1181  /// it will be able to resolve the nodes by ids.
1182  ///
1183  /// \relates LemonReader
1184  template <typename _Graph, typename _Traits = DefaultReaderTraits>
1185  class UndirEdgeSetReader : public LemonReader::SectionReader {
1186    typedef LemonReader::SectionReader Parent;
1187  public:
1188
1189    typedef _Graph Graph;
1190    typedef _Traits Traits;
1191    typedef typename Graph::Node Node;
1192    typedef typename Graph::Edge Edge;
1193    typedef typename Graph::UndirEdge UndirEdge;
1194    typedef typename Traits::Skipper DefaultSkipper;
1195
1196    /// \brief Constructor.
1197    ///
1198    /// Constructor for UndirEdgeSetReader. It creates the UndirEdgeSetReader
1199    /// and attach it into the given LemonReader. The undirected edgeset
1200    /// reader will add the readed undirected edges to the given Graph. It
1201    /// will use the given node id reader to read the source and target
1202    /// nodes of the edges. The reader will read the section only if the
1203    /// \c _id and the \c undiredgset_id are the same.
1204    template <typename NodeIdReader>
1205    UndirEdgeSetReader(LemonReader& _reader,
1206                       Graph& _graph,
1207                       const NodeIdReader& _nodeIdReader,
1208                       const std::string& _id = std::string(),
1209                       const DefaultSkipper& _skipper = DefaultSkipper())
1210      : Parent(_reader), graph(_graph), id(_id), skipper(_skipper) {
1211      checkConcept<_reader_bits::ItemIdReader<Node>, NodeIdReader>();
1212      nodeIdReader.reset(new _reader_bits::
1213                         IdReader<Node, NodeIdReader>(_nodeIdReader));
1214    }
1215    /// \brief Destructor.
1216    ///
1217    /// Destructor for UndirEdgeSetReader.
1218    virtual ~UndirEdgeSetReader() {
1219      for (typename MapReaders::iterator it = readers.begin();
1220           it != readers.end(); ++it) {
1221        delete it->second;
1222      }
1223    }
1224
1225  private:
1226    UndirEdgeSetReader(const UndirEdgeSetReader&);
1227    void operator=(const UndirEdgeSetReader&);
1228
1229  public:
1230
1231    /// \brief Add a new undirected edge map reader command for the reader.
1232    ///
1233    /// Add a new edge undirected map reader command for the reader.
1234    template <typename Map>
1235    UndirEdgeSetReader& readUndirEdgeMap(std::string name, Map& map) {
1236      return _readMap<
1237        typename Traits::template Reader<typename Map::Value>, Map,
1238        typename _reader_bits::Arg<Map>::Type>(name, map);
1239    }
1240
1241    template <typename Map>
1242    UndirEdgeSetReader& readUndirEdgeMap(std::string name, const Map& map) {
1243      return _readMap<
1244        typename Traits::template Reader<typename Map::Value>, Map,
1245        typename _reader_bits::Arg<Map>::Type>(name, map);
1246    }
1247
1248    /// \brief Add a new undirected edge map reader command for the reader.
1249    ///
1250    /// Add a new edge undirected map reader command for the reader.
1251    template <typename Reader, typename Map>
1252    UndirEdgeSetReader& readUndirEdgeMap(std::string name, Map& map,
1253                                         const Reader& reader = Reader()) {
1254      return _readMap<Reader, Map, typename _reader_bits::Arg<Map>::Type>
1255        (name, map, reader);
1256    }
1257
1258    template <typename Reader, typename Map>
1259    UndirEdgeSetReader& readUndirEdgeMap(std::string name, const Map& map,
1260                                         const Reader& reader = Reader()) {
1261      return _readMap<Reader, Map, typename _reader_bits::Arg<Map>::Type >
1262        (name, map, reader);
1263    }
1264
1265  private:
1266
1267    template <typename Reader, typename Map, typename MapParameter>
1268    UndirEdgeSetReader& _readMap(std::string name, MapParameter map,
1269                                 const Reader& reader = Reader()) {
1270      checkConcept<concept::WriteMap<UndirEdge, typename Map::Value>, Map>();
1271      checkConcept<_reader_bits::ItemReader<typename Map::Value>, Reader>();
1272      if (readers.find(name) != readers.end()) {
1273        ErrorMessage msg;
1274        msg << "Multiple read rule for edge map: " << name;
1275        throw IOParameterError(msg.message());
1276      }
1277      readers.insert(
1278        make_pair(name, new _reader_bits::
1279                  MapReader<UndirEdge, Map, Reader>(map, reader)));
1280      return *this;
1281    }
1282
1283  public:
1284
1285    /// \brief Add a new undirected edge map skipper command for the reader.
1286    ///
1287    /// Add a new undirected edge map skipper command for the reader.
1288    template <typename Reader>
1289    UndirEdgeSetReader& skipUndirEdgeMap(std::string name,
1290                                         const Reader& reader = Reader()) {
1291      if (readers.find(name) != readers.end()) {
1292        ErrorMessage msg;
1293        msg << "Multiple read rule for node map: " << name;
1294        throw IOParameterError(msg.message());
1295      }
1296      readers.insert(make_pair(name, new _reader_bits::
1297                               SkipReader<UndirEdge, Reader>(reader)));
1298      return *this;
1299    }
1300
1301    /// \brief Add a new directed edge map reader command for the reader.
1302    ///
1303    /// Add a new directed edge map reader command for the reader.
1304    template <typename Map>
1305    UndirEdgeSetReader& readEdgeMap(std::string name, Map& map) {
1306      return _readDirMap<
1307        typename Traits::template Reader<typename Map::Value>, Map,
1308        typename _reader_bits::Arg<Map>::Type>(name, map);
1309    }
1310
1311    template <typename Map>
1312    UndirEdgeSetReader& readEdgeMap(std::string name, const Map& map) {
1313      return _readDirMap<
1314        typename Traits::template Reader<typename Map::Value>, Map,
1315        typename _reader_bits::Arg<Map>::Type>(name, map);
1316    }
1317
1318    /// \brief Add a new directed edge map reader command for the reader.
1319    ///
1320    /// Add a new directed edge map reader command for the reader.
1321    template <typename Reader, typename Map>
1322    UndirEdgeSetReader& readEdgeMap(std::string name, Map& map,
1323                                    const Reader& reader = Reader()) {
1324      return _readDirMap<Reader, Map, typename _reader_bits::Arg<Map>::Type>
1325        (name, map, reader);
1326    }
1327
1328    template <typename Reader, typename Map>
1329    UndirEdgeSetReader& readEdgeMap(std::string name, const Map& map,
1330                                    const Reader& reader = Reader()) {
1331      return _readDirMap<Reader, Map, typename _reader_bits::Arg<Map>::Type>
1332        (name, map, reader);
1333    }
1334
1335  private:
1336
1337    template <typename Reader, typename Map, typename MapParameter>
1338    UndirEdgeSetReader& _readDirMap(std::string name, MapParameter map,
1339                                    const Reader& reader = Reader()) {
1340      checkConcept<_reader_bits::ItemReader<typename Map::Value>, Reader>();
1341      checkConcept<concept::WriteMap<Edge, typename Map::Value>, Map>();
1342      readMap("+" + name,
1343              _reader_bits::forwardComposeMap(graph, map), reader);
1344      readMap("-" + name,
1345              _reader_bits::backwardComposeMap(graph, map), reader);
1346      return *this;     
1347    }
1348
1349  public:
1350
1351    /// \brief Add a new directed edge map skipper command for the reader.
1352    ///
1353    /// Add a new directed edge map skipper command for the reader.
1354    template <typename Reader>
1355    UndirEdgeSetReader& skipEdgeMap(std::string name,
1356                                    const Reader& reader = Reader()) {
1357      skipMap("+" + name, reader);
1358      skipMap("-" + name, reader);
1359      return *this;
1360    }
1361
1362  protected:
1363
1364    /// \brief Gives back true when the SectionReader can process
1365    /// the section with the given header line.
1366    ///
1367    /// It gives back true when the header line starts with \c \@undiredgeset,
1368    /// and the header line's id and the edgeset's id are the same.
1369    virtual bool header(const std::string& line) {
1370      std::istringstream ls(line);
1371      std::string command;
1372      std::string name;
1373      ls >> command >> name;
1374      return command == "@undiredgeset" && name == id;
1375    }
1376
1377    /// \brief Reader function of the section.
1378    ///
1379    /// It reads the content of the section.
1380    virtual void read(std::istream& is) {
1381      if (!nodeIdReader->isIdReader()) {
1382        throw DataFormatError("Cannot find nodeset or ID map");
1383      }
1384      std::vector<_reader_bits::MapReaderBase<UndirEdge>* > index;
1385      std::string line;
1386
1387      getline(is, line);
1388      std::istringstream ls(line);     
1389      while (ls >> id) {
1390        typename MapReaders::iterator it = readers.find(id);
1391        if (it != readers.end()) {
1392          index.push_back(it->second);
1393          it->second->touch();
1394        } else {
1395          index.push_back(&skipper);
1396        }
1397        if (id == "id" && inverter.get() == 0) {
1398          inverter.reset(index.back()->getInverter());
1399          index.back() = inverter.get();
1400        }
1401      }
1402      for (typename MapReaders::iterator it = readers.begin();
1403           it != readers.end(); ++it) {
1404        if (!it->second->touched()) {
1405          ErrorMessage msg;
1406          msg << "Map not found in file: " << it->first;
1407          throw IOParameterError(msg.message());
1408        }
1409      }
1410      while (getline(is, line)) {       
1411        std::istringstream ls(line);
1412        Node from = nodeIdReader->read(ls);
1413        Node to = nodeIdReader->read(ls);
1414        UndirEdge edge = graph.addEdge(from, to);
1415        for (int i = 0; i < (int)index.size(); ++i) {
1416          index[i]->read(ls, edge);
1417        }
1418      }
1419    }
1420
1421  public:
1422
1423    /// \brief Returns true if the edgeset can give back the edge by its id.
1424    ///
1425    /// Returns true if the edgeset can give back the undirected edge by its
1426    /// id. It is possible only if an "id" named map was read.
1427    bool isIdReader() const {
1428      return inverter.get() != 0;
1429    }
1430
1431    /// \brief Gives back the undirected edge by its id.
1432    ///
1433    /// It reads an id from the stream and gives back which undirected edge
1434    /// belongs to it. It is possible only if there was read an "id" named map.
1435    void readId(std::istream& is, UndirEdge& undirEdge) const {
1436      undirEdge = inverter->read(is);
1437    }
1438
1439    /// \brief Gives back the directed edge by its id.
1440    ///
1441    /// It reads an id from the stream and gives back which directed edge
1442    /// belongs to it. The directed edge id is the \c '+' or \c '-' character
1443    /// and the undirected edge id. It is possible only if there was read
1444    /// an "id" named map.
1445    void readId(std::istream& is, Edge& edge) const {
1446      char c;
1447      is >> c;
1448      UndirEdge undirEdge = inverter->read(is);
1449      if (c == '+') {
1450        edge = graph.direct(undirEdge, true);
1451      } else if (c == '-') {
1452        edge = graph.direct(undirEdge, false);
1453      } else {
1454        throw DataFormatError("Wrong id format for edge "
1455                              "in undirected edgeset");
1456      }
1457    }
1458
1459  private:
1460
1461    typedef std::map<std::string,
1462                     _reader_bits::MapReaderBase<UndirEdge>*> MapReaders;
1463    MapReaders readers;
1464   
1465    Graph& graph;   
1466    std::string id;
1467    _reader_bits::SkipReader<UndirEdge, DefaultSkipper> skipper;
1468
1469    std::auto_ptr<_reader_bits::MapInverterBase<UndirEdge> > inverter;
1470    std::auto_ptr<_reader_bits::IdReaderBase<Node> > nodeIdReader;
1471  };
1472
1473  /// \ingroup io_group
1474  /// \brief SectionReader for reading labeled nodes.
1475  ///
1476  /// The nodes section's header line is \c \@nodes \c nodes_id, but the
1477  /// \c nodes_id may be empty.
1478  ///
1479  /// Each line in the section contains the name of the node
1480  /// and then the node id.
1481  ///
1482  /// \relates LemonReader
1483  template <typename _Graph>
1484  class NodeReader : public LemonReader::SectionReader {
1485    typedef LemonReader::SectionReader Parent;
1486    typedef _Graph Graph;
1487    typedef typename Graph::Node Node;
1488  public:
1489   
1490    /// \brief Constructor.
1491    ///
1492    /// Constructor for NodeReader. It creates the NodeReader and
1493    /// attach it into the given LemonReader. It will use the given
1494    /// node id reader to give back the nodes. The reader will read the
1495    /// section only if the \c _id and the \c nodes_id are the same.
1496    template <typename _IdReader>
1497    NodeReader(LemonReader& _reader, const _IdReader& _idReader,
1498               const std::string& _id = std::string())
1499      : Parent(_reader), id(_id) {
1500      checkConcept<_reader_bits::ItemIdReader<Node>, _IdReader>();
1501      nodeIdReader.reset(new _reader_bits::
1502                         IdReader<Node, _IdReader>(_idReader));
1503    }
1504
1505    /// \brief Destructor.
1506    ///
1507    /// Destructor for NodeReader.
1508    virtual ~NodeReader() {}
1509
1510  private:
1511    NodeReader(const NodeReader&);
1512    void operator=(const NodeReader&);
1513
1514  public:
1515
1516    /// \brief Add a node reader command for the NodeReader.
1517    ///
1518    /// Add a node reader command for the NodeReader.
1519    void readNode(const std::string& name, Node& item) {
1520      if (readers.find(name) != readers.end()) {
1521        ErrorMessage msg;
1522        msg << "Multiple read rule for node: " << name;
1523        throw IOParameterError(msg.message());
1524      }
1525      readers.insert(make_pair(name, _reader_bits::ItemStore<Node>(item)));
1526    }
1527
1528  protected:
1529
1530    /// \brief Gives back true when the SectionReader can process
1531    /// the section with the given header line.
1532    ///
1533    /// It gives back true when the header line start with \c \@nodes,
1534    /// and the header line's id and the reader's id are the same.
1535    virtual bool header(const std::string& line) {
1536      std::istringstream ls(line);
1537      std::string command;
1538      std::string name;
1539      ls >> command >> name;
1540      return command == "@nodes" && name == id;
1541    }
1542
1543    /// \brief Reader function of the section.
1544    ///
1545    /// It reads the content of the section.
1546    virtual void read(std::istream& is) {
1547      if (!nodeIdReader->isIdReader()) {
1548        throw DataFormatError("Cannot find nodeset or ID map");
1549      }
1550      std::string line;
1551      while (getline(is, line)) {
1552        std::istringstream ls(line);
1553        std::string id;
1554        ls >> id;
1555        typename NodeReaders::iterator it = readers.find(id);
1556        if (it != readers.end()) {
1557          it->second.read(nodeIdReader->read(ls));
1558          it->second.touch();
1559        }       
1560      }
1561      for (typename NodeReaders::iterator it = readers.begin();
1562           it != readers.end(); ++it) {
1563        if (!it->second.touched()) {
1564          ErrorMessage msg;
1565          msg << "Node not found in file: " << it->first;
1566          throw IOParameterError(msg.message());
1567        }
1568      }
1569    }
1570   
1571  private:
1572
1573    std::string id;
1574
1575    typedef std::map<std::string, _reader_bits::ItemStore<Node> > NodeReaders;
1576    NodeReaders readers;
1577    std::auto_ptr<_reader_bits::IdReaderBase<Node> > nodeIdReader;
1578  };
1579
1580  /// \ingroup io_group
1581  /// \brief SectionReader for reading labeled edges.
1582  ///
1583  /// The edges section's header line is \c \@edges \c edges_id, but the
1584  /// \c edges_id may be empty.
1585  ///
1586  /// Each line in the section contains the name of the edge
1587  /// and then the edge id.
1588  ///
1589  /// \relates LemonReader
1590  template <typename _Graph>
1591  class EdgeReader : public LemonReader::SectionReader {
1592    typedef LemonReader::SectionReader Parent;
1593    typedef _Graph Graph;
1594    typedef typename Graph::Edge Edge;
1595  public:
1596   
1597    /// \brief Constructor.
1598    ///
1599    /// Constructor for EdgeReader. It creates the EdgeReader and
1600    /// attach it into the given LemonReader. It will use the given
1601    /// edge id reader to give back the edges. The reader will read the
1602    /// section only if the \c _id and the \c edges_id are the same.
1603    template <typename _IdReader>
1604    EdgeReader(LemonReader& _reader, const _IdReader& _idReader,
1605               const std::string& _id = std::string())
1606      : Parent(_reader), id(_id) {
1607      checkConcept<_reader_bits::ItemIdReader<Edge>, _IdReader>();
1608      edgeIdReader.reset(new _reader_bits::
1609                         IdReader<Edge, _IdReader>(_idReader));
1610    }
1611
1612    /// \brief Destructor.
1613    ///
1614    /// Destructor for EdgeReader.
1615    virtual ~EdgeReader() {}
1616  private:
1617    EdgeReader(const EdgeReader&);
1618    void operator=(const EdgeReader&);
1619
1620  public:
1621
1622    /// \brief Add an edge reader command for the EdgeReader.
1623    ///
1624    /// Add an edge reader command for the EdgeReader.
1625    void readEdge(const std::string& name, Edge& item) {
1626      if (readers.find(name) != readers.end()) {
1627        ErrorMessage msg;
1628        msg << "Multiple read rule for edge: " << name;
1629        throw IOParameterError(msg.message());
1630      }
1631      readers.insert(make_pair(name, _reader_bits::ItemStore<Edge>(item)));
1632    }
1633
1634  protected:
1635
1636    /// \brief Gives back true when the SectionReader can process
1637    /// the section with the given header line.
1638    ///
1639    /// It gives back true when the header line start with \c \@edges,
1640    /// and the header line's id and the reader's id are the same.
1641    virtual bool header(const std::string& line) {
1642      std::istringstream ls(line);
1643      std::string command;
1644      std::string name;
1645      ls >> command >> name;
1646      return command == "@edges" && name == id;
1647    }
1648
1649    /// \brief Reader function of the section.
1650    ///
1651    /// It reads the content of the section.
1652    virtual void read(std::istream& is) {
1653      if (!edgeIdReader->isIdReader()) {
1654        throw DataFormatError("Cannot find edgeset or ID map");
1655      }
1656      std::string line;
1657      while (getline(is, line)) {
1658        std::istringstream ls(line);
1659        std::string id;
1660        ls >> id;
1661        typename EdgeReaders::iterator it = readers.find(id);
1662        if (it != readers.end()) {
1663          it->second.read(edgeIdReader->read(ls));
1664          it->second.touch();
1665        }       
1666      }
1667      for (typename EdgeReaders::iterator it = readers.begin();
1668           it != readers.end(); ++it) {
1669        if (!it->second.touched()) {
1670          ErrorMessage msg;
1671          msg << "Edge not found in file: " << it->first;
1672          throw IOParameterError(msg.message());
1673        }
1674      }
1675    }
1676   
1677  private:
1678
1679    std::string id;
1680
1681    typedef std::map<std::string, _reader_bits::ItemStore<Edge> > EdgeReaders;
1682    EdgeReaders readers;
1683    std::auto_ptr<_reader_bits::IdReaderBase<Edge> > edgeIdReader;
1684  };
1685
1686  /// \ingroup io_group
1687  /// \brief SectionReader for reading labeled undirected edges.
1688  ///
1689  /// The undirected edges section's header line is \c \@undiredges
1690  /// \c undiredges_id, but the \c undiredges_id may be empty.
1691  ///
1692  /// Each line in the section contains the name of the undirected edge
1693  /// and then the undirected edge id.
1694  ///
1695  /// \relates LemonReader
1696  template <typename _Graph>
1697  class UndirEdgeReader : public LemonReader::SectionReader {
1698    typedef LemonReader::SectionReader Parent;
1699    typedef _Graph Graph;
1700    typedef typename Graph::Edge Edge;
1701    typedef typename Graph::UndirEdge UndirEdge;
1702  public:
1703   
1704    /// \brief Constructor.
1705    ///
1706    /// Constructor for UndirEdgeReader. It creates the UndirEdgeReader and
1707    /// attach it into the given LemonReader. It will use the given
1708    /// undirected edge id reader to give back the edges. The reader will
1709    /// read the section only if the \c _id and the \c undiredges_id are
1710    /// the same.
1711    template <typename _IdReader>
1712    UndirEdgeReader(LemonReader& _reader, const _IdReader& _idReader,
1713               const std::string& _id = std::string())
1714      : Parent(_reader), id(_id) {
1715      checkConcept<_reader_bits::ItemIdReader<UndirEdge>, _IdReader>();
1716      checkConcept<_reader_bits::ItemIdReader<Edge>, _IdReader>();
1717      undirEdgeIdReader.reset(new _reader_bits::
1718                              IdReader<UndirEdge, _IdReader>(_idReader));
1719      edgeIdReader.reset(new _reader_bits::
1720                         IdReader<Edge, _IdReader>(_idReader));
1721    }
1722
1723    /// \brief Destructor.
1724    ///
1725    /// Destructor for UndirEdgeReader.
1726    virtual ~UndirEdgeReader() {}
1727  private:
1728    UndirEdgeReader(const UndirEdgeReader&);
1729    void operator=(const UndirEdgeReader&);
1730
1731  public:
1732
1733    /// \brief Add an undirected edge reader command for the UndirEdgeReader.
1734    ///
1735    /// Add an undirected edge reader command for the UndirEdgeReader.
1736    void readUndirEdge(const std::string& name, UndirEdge& item) {
1737      if (undirEdgeReaders.find(name) != undirEdgeReaders.end()) {
1738        ErrorMessage msg;
1739        msg << "Multiple read rule for undirected edge: " << name;
1740        throw IOParameterError(msg.message());
1741      }
1742      undirEdgeReaders.insert(make_pair(name, _reader_bits::
1743                                        ItemStore<UndirEdge>(item)));
1744    }
1745
1746    /// \brief Add an edge reader command for the UndirEdgeReader.
1747    ///
1748    /// Add an edge reader command for the UndirEdgeReader.
1749    void readEdge(const std::string& name, Edge& item) {
1750      if (edgeReaders.find(name) != edgeReaders.end()) {
1751        ErrorMessage msg;
1752        msg << "Multiple read rule for edge: " << name;
1753        throw IOParameterError(msg.message());
1754      }
1755      edgeReaders.insert(make_pair(name, _reader_bits::ItemStore<Edge>(item)));
1756    }
1757
1758  protected:
1759
1760    /// \brief Gives back true when the SectionReader can process
1761    /// the section with the given header line.
1762    ///
1763    /// It gives back true when the header line start with \c \@edges,
1764    /// and the header line's id and the reader's id are the same.
1765    virtual bool header(const std::string& line) {
1766      std::istringstream ls(line);
1767      std::string command;
1768      std::string name;
1769      ls >> command >> name;
1770      return command == "@undiredges" && name == id;
1771    }
1772
1773    /// \brief Reader function of the section.
1774    ///
1775    /// It reads the content of the section.
1776    virtual void read(std::istream& is) {
1777      if (!edgeIdReader->isIdReader()) {
1778        throw DataFormatError("Cannot find undirected edgeset or ID map");
1779      }
1780      if (!undirEdgeIdReader->isIdReader()) {
1781        throw DataFormatError("Cannot find undirected edgeset or ID map");
1782      }
1783      std::string line;
1784      while (getline(is, line)) {
1785        std::istringstream ls(line);
1786        std::string id;
1787        ls >> id;
1788        {
1789          typename UndirEdgeReaders::iterator it = undirEdgeReaders.find(id);
1790          if (it != undirEdgeReaders.end()) {
1791            it->second.read(undirEdgeIdReader->read(ls));
1792            it->second.touch();
1793            continue;
1794          }     
1795        } {
1796          typename EdgeReaders::iterator it = edgeReaders.find(id);
1797          if (it != edgeReaders.end()) {
1798            it->second.read(edgeIdReader->read(ls));
1799            it->second.touch();
1800            continue;
1801          }     
1802        }
1803      }
1804      for (typename EdgeReaders::iterator it = edgeReaders.begin();
1805           it != edgeReaders.end(); ++it) {
1806        if (!it->second.touched()) {
1807          ErrorMessage msg;
1808          msg << "Edge not found in file: " << it->first;
1809          throw IOParameterError(msg.message());
1810        }
1811      }
1812      for (typename UndirEdgeReaders::iterator it = undirEdgeReaders.begin();
1813           it != undirEdgeReaders.end(); ++it) {
1814        if (!it->second.touched()) {
1815          ErrorMessage msg;
1816          msg << "UndirEdge not found in file: " << it->first;
1817          throw IOParameterError(msg.message());
1818        }
1819      }
1820    }
1821   
1822  private:
1823
1824    std::string id;
1825
1826    typedef std::map<std::string,
1827                     _reader_bits::ItemStore<UndirEdge> > UndirEdgeReaders;
1828    UndirEdgeReaders undirEdgeReaders;
1829    std::auto_ptr<_reader_bits::IdReaderBase<UndirEdge> > undirEdgeIdReader;
1830
1831    typedef std::map<std::string, _reader_bits::ItemStore<Edge> > EdgeReaders;
1832    EdgeReaders edgeReaders;
1833    std::auto_ptr<_reader_bits::IdReaderBase<Edge> > edgeIdReader;
1834  };
1835
1836  /// \ingroup io_group
1837  /// \brief SectionReader for attributes.
1838  ///
1839  /// The lemon format can store multiple attribute set. Each set has
1840  /// the header line \c \@attributes \c attributeset_id, but the
1841  /// attributeset_id may be empty.
1842  ///
1843  /// The attributeset section contains several lines. Each of them starts
1844  /// with an attribute and then a the value for the id.
1845  ///
1846  /// \relates LemonReader
1847  template <typename _Traits = DefaultReaderTraits>
1848  class AttributeReader : public LemonReader::SectionReader {
1849    typedef LemonReader::SectionReader Parent;
1850    typedef _Traits Traits;
1851  public:
1852    /// \brief Constructor.
1853    ///
1854    /// Constructor for AttributeReader. It creates the AttributeReader and
1855    /// attach it into the given LemonReader. The reader process a section
1856    /// only if the \c section_id and the \c _id are the same.
1857    AttributeReader(LemonReader& _reader,
1858                    const std::string& _id = std::string())
1859      : Parent(_reader), id(_id) {}
1860
1861    /// \brief Destructor.
1862    ///
1863    /// Destructor for AttributeReader.
1864    virtual ~AttributeReader() {
1865      for (typename Readers::iterator it = readers.begin();
1866           it != readers.end(); ++it) {
1867        delete it->second;
1868      }
1869    }
1870
1871  private:
1872    AttributeReader(const AttributeReader&);
1873    void operator=(AttributeReader&);
1874
1875  public:
1876    /// \brief Add an attribute reader command for the reader.
1877    ///
1878    /// Add an attribute reader command for the reader.
1879    template <typename Value>
1880    AttributeReader& readAttribute(const std::string& id, Value& value) {
1881      return readAttribute<typename Traits::template Reader<Value> >
1882        (id, value);
1883    }
1884
1885    /// \brief Add an attribute reader command for the reader.
1886    ///
1887    /// Add an attribute reader command for the reader.
1888    template <typename Reader, typename Value>
1889    AttributeReader& readAttribute(const std::string& name, Value& value,
1890                                   const Reader& reader = Reader()) {
1891      checkConcept<_reader_bits::ItemReader<Value>, Reader>();
1892      if (readers.find(name) != readers.end()) {
1893        ErrorMessage msg;
1894        msg << "Multiple read rule for attribute: " << name;
1895        throw IOParameterError(msg.message());
1896      }
1897      readers.insert(make_pair(name, new _reader_bits::
1898                               ValueReader<Value, Reader>(value, reader)));
1899      return *this;
1900    }
1901
1902  protected:
1903
1904    /// \brief Gives back true when the SectionReader can process
1905    /// the section with the given header line.
1906    ///
1907    /// It gives back true when the header line start with \c \@attributes,
1908    /// and the header line's id and the attributeset's id are the same.
1909    bool header(const std::string& line) {
1910      std::istringstream ls(line);
1911      std::string command;
1912      std::string name;
1913      ls >> command >> name;
1914      return command == "@attributes" && name == id;
1915    }
1916
1917    /// \brief Reader function of the section.
1918    ///
1919    /// It reads the content of the section.
1920    void read(std::istream& is) {
1921      std::string line;
1922      while (getline(is, line)) {
1923        std::istringstream ls(line);
1924        std::string id;
1925        ls >> id;
1926        typename Readers::iterator it = readers.find(id);
1927        if (it != readers.end()) {
1928          it->second->read(ls);
1929        }
1930      }
1931    }   
1932
1933  private:
1934    std::string id;
1935
1936    typedef std::map<std::string, _reader_bits::ValueReaderBase*> Readers;
1937    Readers readers; 
1938  };
1939
1940  /// \ingroup io_group
1941  /// \brief SectionReader for retrieve what is in the file.
1942  ///
1943  /// SectionReader for retrieve what is in the file. If you want
1944  /// to know which sections, maps and items are in the file
1945  /// use the next code:
1946  /// \code
1947  /// LemonReader reader("input.lgf");
1948  /// ContentReader content(reader);
1949  /// reader.run();
1950  /// \endcode
1951  class ContentReader : public LemonReader::SectionReader {
1952    typedef LemonReader::SectionReader Parent;
1953  public:
1954    /// \brief Constructor.
1955    ///
1956    /// Constructor for
1957    ContentReader(LemonReader& _reader) : Parent(_reader) {}
1958
1959    /// \brief Desctructor.
1960    ///
1961    /// Desctructor.
1962    virtual ~ContentReader() {}
1963
1964    /// \brief Gives back how many nodesets are in the file.
1965    ///
1966    /// Gives back how many nodesets are in the file.
1967    int nodeSetNum() const {
1968      return nodesets.size();
1969    }
1970
1971    /// \brief Gives back the name of nodeset on the indiced position.
1972    ///
1973    /// Gives back the name of nodeset on the indiced position.
1974    std::string nodeSetName(int index) const {
1975      return nodesets[index].name;
1976    }
1977
1978    /// \brief Gives back the map names of nodeset on the indiced position.
1979    ///
1980    /// Gives back the map names of nodeset on the indiced position.
1981    const std::vector<std::string>& nodeSetMaps(int index) const {
1982      return nodesets[index].items;
1983    }
1984
1985    /// \brief Gives back how many edgesets are in the file.
1986    ///
1987    /// Gives back how many edgesets are in the file.
1988    int edgeSetNum() const {
1989      return edgesets.size();
1990    }
1991
1992    /// \brief Gives back the name of edgeset on the indiced position.
1993    ///
1994    /// Gives back the name of edgeset on the indiced position.
1995    std::string edgeSetName(int index) const {
1996      return edgesets[index].name;
1997    }
1998
1999    /// \brief Gives back the map names of edgeset on the indiced position.
2000    ///
2001    /// Gives back the map names of edgeset on the indiced position.
2002    const std::vector<std::string>& edgeSetMaps(int index) const {
2003      return edgesets[index].items;
2004    }
2005
2006    /// \brief Gives back how many undirected edgesets are in the file.
2007    ///
2008    /// Gives back how many undirected edgesets are in the file.
2009    int undirEdgeSetNum() const {
2010      return undiredgesets.size();
2011    }
2012
2013    /// \brief Gives back the name of undirected edgeset on the indiced
2014    /// position.
2015    ///
2016    /// Gives back the name of undirected edgeset on the indiced position.
2017    std::string undirEdgeSetName(int index) const {
2018      return undiredgesets[index].name;
2019    }
2020
2021    /// \brief Gives back the map names of undirected edgeset on the indiced
2022    /// position.
2023    ///
2024    /// Gives back the map names of undirected edgeset on the indiced position.
2025    const std::vector<std::string>& undirEdgeSetMaps(int index) const {
2026      return undiredgesets[index].items;
2027    }
2028
2029    /// \brief Gives back how many labeled nodes section are in the file.
2030    ///
2031    /// Gives back how many labeled nodes section are in the file.
2032    int nodesNum() const {
2033      return nodes.size();
2034    }
2035
2036    /// \brief Gives back the name of labeled nodes section on the indiced
2037    /// position.
2038    ///
2039    /// Gives back the name of labeled nodes section on the indiced position.
2040    std::string nodesName(int index) const {
2041      return nodes[index].name;
2042    }
2043
2044    /// \brief Gives back the names of the labeled nodes in the indiced
2045    /// section.
2046    ///
2047    /// Gives back the names of the labeled nodes in the indiced section.
2048    const std::vector<std::string>& nodesItems(int index) const {
2049      return nodes[index].items;
2050    }
2051
2052    /// \brief Gives back how many labeled edges section are in the file.
2053    ///
2054    /// Gives back how many labeled edges section are in the file.
2055    int edgesNum() const {
2056      return edges.size();
2057    }
2058
2059    /// \brief Gives back the name of labeled edges section on the indiced
2060    /// position.
2061    ///
2062    /// Gives back the name of labeled edges section on the indiced position.
2063    std::string edgesName(int index) const {
2064      return edges[index].name;
2065    }
2066
2067    /// \brief Gives back the names of the labeled edges in the indiced
2068    /// section.
2069    ///
2070    /// Gives back the names of the labeled edges in the indiced section.
2071    const std::vector<std::string>& edgesItems(int index) const {
2072      return edges[index].items;
2073    }
2074 
2075    /// \brief Gives back how many labeled undirected edges section are
2076    /// in the file.
2077    ///
2078    /// Gives back how many labeled undirected edges section are in the file.
2079    int undirEdgesNum() const {
2080      return undiredges.size();
2081    }
2082
2083    /// \brief Gives back the name of labeled undirected edges section
2084    /// on the indiced position.
2085    ///
2086    /// Gives back the name of labeled undirected edges section on the
2087    /// indiced position.
2088    std::string undirEdgesName(int index) const {
2089      return undiredges[index].name;
2090    }
2091
2092    /// \brief Gives back the names of the labeled undirected edges in
2093    /// the indiced section.
2094    ///
2095    /// Gives back the names of the labeled undirected edges in the
2096    /// indiced section.
2097    const std::vector<std::string>& undirEdgesItems(int index) const {
2098      return undiredges[index].items;
2099    }
2100
2101 
2102    /// \brief Gives back how many attributes section are in the file.
2103    ///
2104    /// Gives back how many attributes section are in the file.
2105    int attributesNum() const {
2106      return attributes.size();
2107    }
2108
2109    /// \brief Gives back the name of attributes section on the indiced
2110    /// position.
2111    ///
2112    /// Gives back the name of attributes section on the indiced position.
2113    std::string attributesName(int index) const {
2114      return attributes[index].name;
2115    }
2116
2117    /// \brief Gives back the names of the attributes in the indiced section.
2118    ///
2119    /// Gives back the names of the attributes in the indiced section.
2120    const std::vector<std::string>& attributesItems(int index) const {
2121      return attributes[index].items;
2122    }
2123
2124    const std::vector<std::string>& otherSections() const {
2125      return sections;
2126    }
2127
2128  protected:
2129   
2130    /// \brief Gives back true when the SectionReader can process
2131    /// the section with the given header line.
2132    ///
2133    /// It gives back true when the section is common section.
2134    bool header(const std::string& line) {
2135      std::istringstream ls(line);
2136      std::string command, name;
2137      ls >> command >> name;
2138      if (command == "@nodeset") {
2139        current = command;
2140        nodesets.push_back(SectionInfo(name));
2141      } else if (command == "@edgeset") {
2142        current = command;
2143        edgesets.push_back(SectionInfo(name));
2144      } else if (command == "@undiredgeset") {
2145        current = command;
2146        undiredgesets.push_back(SectionInfo(name));
2147      } else if (command == "@nodes") {
2148        current = command;
2149        nodes.push_back(SectionInfo(name));
2150      } else if (command == "@edges") {
2151        current = command;
2152        edges.push_back(SectionInfo(name));
2153      } else if (command == "@undiredges") {
2154        current = command;
2155        undiredges.push_back(SectionInfo(name));
2156      } else if (command == "@attributes") {
2157        current = command;
2158        attributes.push_back(SectionInfo(name));
2159      } else {
2160        sections.push_back(line);
2161        return false;
2162      }
2163      return true;
2164    }
2165
2166    /// \brief Retrieve the items from various sections.
2167    ///
2168    /// Retrieve the items from various sections.
2169    void read(std::istream& is) {
2170      if (current == "@nodeset") {
2171        readMapNames(is, nodesets.back().items);
2172      } else if (current == "@edgeset") {
2173        readMapNames(is, edgesets.back().items);
2174      } else if (current == "@undiredgeset") {
2175        readMapNames(is, undiredgesets.back().items);
2176      } else if (current == "@nodes") {
2177        readItemNames(is, nodes.back().items);
2178      } else if (current == "@edges") {
2179        readItemNames(is, edges.back().items);
2180      } else if (current == "@undiredges") {
2181        readItemNames(is, undiredges.back().items);
2182      } else if (current == "@attributes") {
2183        readItemNames(is, attributes.back().items);
2184      }
2185    }   
2186
2187  private:
2188
2189    void readMapNames(std::istream& is, std::vector<std::string>& maps) {
2190      std::string line, id;
2191      std::getline(is, line);
2192      std::istringstream ls(line);
2193      while (ls >> id) {
2194        maps.push_back(id);
2195      }
2196      while (getline(is, line));
2197    }
2198
2199    void readItemNames(std::istream& is, std::vector<std::string>& maps) {
2200      std::string line, id;
2201      while (std::getline(is, line)) {
2202        std::istringstream ls(line);
2203        ls >> id;
2204        maps.push_back(id);
2205      }
2206    }
2207
2208    struct SectionInfo {
2209      std::string name;
2210      std::vector<std::string> items;
2211
2212      SectionInfo(const std::string& _name) : name(_name) {}
2213    };
2214
2215    std::vector<SectionInfo> nodesets;
2216    std::vector<SectionInfo> edgesets;
2217    std::vector<SectionInfo> undiredgesets;
2218
2219    std::vector<SectionInfo> nodes;
2220    std::vector<SectionInfo> edges;
2221    std::vector<SectionInfo> undiredges;
2222
2223    std::vector<SectionInfo> attributes;
2224
2225    std::vector<std::string> sections;
2226
2227    std::string current;
2228
2229  };
2230
2231}
2232#endif
Note: See TracBrowser for help on using the repository browser.