COIN-OR::LEMON - Graph Library

source: lemon-0.x/src/lemon/lemon_reader.h @ 1416:1b481ced25e7

Last change on this file since 1416:1b481ced25e7 was 1409:d2d1f8fa187b, checked in by Balazs Dezso, 20 years ago

LemonWriter? and GraphWriter?.
Little bit better documentation.

File size: 33.1 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#ifndef LEMON_LEMON_READER_H
22#define LEMON_LEMON_READER_H
23
24#include <iostream>
25#include <fstream>
26#include <string>
27#include <vector>
28#include <algorithm>
29#include <map>
30#include <memory>
31
32#include <lemon/error.h>
33#include <lemon/bits/item_reader.h>
34
35
36namespace lemon {
37
38  /// \ingroup io_group
39  /// \brief Lemon Format reader class.
40  ///
41  /// The Lemon Format contains several sections. We do not want to
42  /// determine what sections are in a lemon file we give only a framework
43  /// to read a section oriented format.
44  ///
45  /// In the Lemon Format each section starts with a line contains a \c \@
46  /// character on the first not white space position. This line is the
47  /// header line of the section. Each next lines belong to this section
48  /// while it does not starts with \c \@ character. This line can start a
49  /// new section or if it can close the file with the \c \@end line.
50  /// The file format ignore the empty lines and it may contain comments
51  /// started with a \c # character to the end of the line.
52  ///
53  /// The framework provides an abstract LemonReader::SectionReader class
54  /// what defines the interface of a SectionReader. The SectionReader
55  /// has the \c header() member function what get a header line string and
56  /// decides if it want to process the next section. Several SectionReaders
57  /// can be attached to an LemonReader and the first attached what can
58  /// process the section will be used. Its \c read() member will called
59  /// with a stream contains the section. From this stream the empty lines
60  /// and comments are filtered out.
61  ///
62  /// \relates GraphReader
63  /// \relates NodeSetReader
64  /// \relates EdgeSetReader
65  /// \relates NodesReader
66  /// \relates EdgesReader
67  /// \relates AttributeReader
68  class LemonReader {
69  private:
70   
71    class FilterStreamBuf : public std::streambuf {
72    public:
73
74      typedef std::streambuf Parent;
75      typedef Parent::char_type char_type;
76      FilterStreamBuf(std::istream& is, int& num)
77        : _is(is), _base(0), _eptr(0),
78          _num(num), skip_state(after_endl) {}
79
80    protected:
81
82      enum skip_state_type {
83        no_skip,
84        after_comment,
85        after_endl,
86        empty_line
87      };
88
89      char_type small_buf[1];
90
91
92      std::istream& _is;
93
94      char_type* _base;
95      char_type* _eptr;
96
97      int& _num;
98
99      skip_state_type skip_state;
100
101
102      char_type* base() { return _base; }
103
104      char_type* eptr() { return _eptr; }
105
106      int blen() { return _eptr - _base; }
107
108      void setb(char_type* buf, int len) {
109        _base = buf;
110        _eptr = buf + len;
111      }
112 
113      virtual std::streambuf* setbuf(char *buf, int len) {
114        if (base()) return 0;
115        if (buf != 0 && len >= (int)sizeof(small_buf)) {
116          setb(buf, len);
117        } else {
118          setb(small_buf, sizeof(small_buf));
119        }
120        setg(0, 0, 0);
121        return this;
122      }
123
124      bool put_char(char c) {
125        switch (skip_state) {
126        case no_skip:
127          switch (c) {
128          case '\n':
129            skip_state = after_endl;
130            return true;
131          case '#':
132            skip_state = after_comment;
133            return false;
134          default:
135            return true;
136          }
137        case after_comment:
138          switch (c) {
139          case '\n':
140            skip_state = after_endl;
141            return true;
142          default:
143            return false;
144          }       
145        case after_endl:
146          switch (c) {
147          case '@':
148            return false;
149          case '\n':
150            return false;
151          case '#':
152            skip_state = empty_line;
153            return false;
154          default:
155            if (!isspace(c)) {
156              skip_state = no_skip;
157              return true;
158            } else {
159              return false;
160            }
161          }
162          break;
163        case empty_line:
164          switch (c) {
165          case '\n':
166            skip_state = after_endl;
167            return false;
168          default:
169            return false;
170          }
171        }
172        return false;
173      }
174
175      virtual int underflow() {
176        char c;
177        if (_is.read(&c, 1)) {
178          _is.putback(c);
179          if (c == '@') {
180            return EOF;
181          }
182        } else {
183          return EOF;
184        }
185        char_type *ptr;
186        for (ptr = base(); ptr != eptr(); ++ptr) {
187          if (_is.read(&c, 1)) {
188            if (c == '\n') ++_num;
189            if (put_char(c)) {
190              *ptr = c;
191            } else {
192              if (skip_state == after_endl && c == '@') {
193                _is.putback('@');
194                break;
195              }
196              --ptr;
197            }
198          } else {
199            break;
200          }
201        }
202        setg(base(), base(), ptr);
203        return *base();
204      }
205
206      virtual int sync() {
207        return EOF;
208      }
209    };
210
211  public:
212
213    /// \brief Abstract base class for reading a section.
214    ///
215    /// This class has an \c header() member function what get a
216    /// header line string and decides if it want to process the next
217    /// section. Several SectionReaders can be attached to an LemonReader
218    /// and the first attached what can process the section will be used.
219    /// Its \c read() member will called with a stream contains the section.
220    /// From this stream the empty lines and comments are filtered out.
221    class SectionReader {
222      friend class LemonReader;
223    protected:
224      /// \brief Constructor for SectionReader.
225      ///
226      /// Constructor for SectionReader. It attach this reader to
227      /// the given LemonReader.
228      SectionReader(LemonReader& reader) {
229        reader.attach(*this);
230      }
231
232      /// \brief Gives back true when the SectionReader can process
233      /// the section with the given header line.
234      ///
235      /// It gives back true when the SectionReader can process
236      /// the section with the given header line.
237      virtual bool header(const std::string& line) = 0;
238
239      /// \brief Reader function of the section.
240      ///
241      /// It reads the content of the section.
242      virtual void read(std::istream& is) = 0;
243    };
244
245    /// \brief Constructor for LemonReader.
246    ///
247    /// Constructor for LemonReader which reads from the given stream.
248    LemonReader(std::istream& _is)
249      : is(&_is), own_is(false) {}
250
251    /// \brief Constructor for LemonReader.
252    ///
253    /// Constructor for LemonReader which reads from the given file.
254    LemonReader(const std::string& filename)
255      : is(0), own_is(true) {
256      is = new std::ifstream(filename.c_str());
257    }
258
259    /// \brief Desctructor for LemonReader.
260    ///
261    /// Desctructor for LemonReader.
262    ~LemonReader() {
263      if (own_is) {
264        delete is;
265      }
266    }
267
268  private:
269    LemonReader(const LemonReader&);
270    void operator=(const LemonReader&);
271
272    void attach(SectionReader& reader) {
273      readers.push_back(&reader);
274    }
275
276  public:
277    /// \brief Executes the LemonReader.
278    ///
279    /// It executes the LemonReader.
280    void run() {
281      int line_num = 0;
282      std::string line;
283      try {
284        while ((++line_num, getline(*is, line)) && line.find("@end") != 0) {
285          SectionReaders::iterator it;
286          for (it = readers.begin(); it != readers.end(); ++it) {
287            if ((*it)->header(line)) {
288              char buf[2048];
289              FilterStreamBuf buffer(*is, line_num);
290              buffer.pubsetbuf(buf, sizeof(buf));
291              std::istream is(&buffer);
292              (*it)->read(is);
293              break;
294            }
295          }
296        }
297      } catch (DataFormatError& error) {
298        error.line(line_num);
299        throw error;
300      }
301    }
302
303
304  private:
305
306    std::istream* is;
307    bool own_is;
308
309    typedef std::vector<SectionReader*> SectionReaders;
310    SectionReaders readers;
311
312  };
313
314  /// \brief Helper class for implementing the common SectionReaders.
315  ///
316  /// Helper class for implementing the common SectionReaders.
317  class CommonSectionReaderBase : public LemonReader::SectionReader {
318    typedef LemonReader::SectionReader Parent;
319  protected:
320   
321    /// \brief Constructor for CommonSectionReaderBase.
322    ///
323    /// Constructor for CommonSectionReaderBase. It attach this reader to
324    /// the given LemonReader.
325    CommonSectionReaderBase(LemonReader& _reader)
326      : Parent(_reader) {}
327
328    template <typename _Item>
329    class ReaderBase;
330   
331    template <typename _Item>
332    class InverterBase : public ReaderBase<_Item> {
333    public:
334      typedef _Item Item;
335      virtual void read(std::istream&, const Item&) = 0;
336      virtual Item read(std::istream&) const = 0;
337
338      virtual InverterBase<_Item>* getInverter() {
339        return this;
340      }
341
342
343    };
344
345    template <typename _Item, typename _Map, typename _Reader>
346    class MapReaderInverter : public InverterBase<_Item> {
347    public:
348      typedef _Item Item;
349      typedef _Reader Reader;
350      typedef typename Reader::Value Value;
351      typedef _Map Map;
352      typedef std::map<Value, Item> Inverse;
353
354      Map& map;
355      Reader reader;
356      Inverse inverse;
357
358      MapReaderInverter(Map& _map, const Reader& _reader)
359        : map(_map), reader(_reader) {}
360
361      virtual ~MapReaderInverter() {}
362
363      virtual void read(std::istream& is, const Item& item) {
364        Value value;
365        reader.read(is, value);
366        map.set(item, value);
367        typename Inverse::iterator it = inverse.find(value);
368        if (it == inverse.end()) {
369          inverse.insert(std::make_pair(value, item));
370        } else {
371          throw DataFormatError("Multiple ID occurence");
372        }
373      }
374
375      virtual Item read(std::istream& is) const {
376        Value value;
377        reader.read(is, value);
378        typename Inverse::const_iterator it = inverse.find(value);
379        if (it != inverse.end()) {
380          return it->second;
381        } else {
382          throw DataFormatError("Invalid ID error");
383        }
384      }     
385
386    };
387
388    template <typename _Item, typename _Reader>
389    class SkipReaderInverter : public InverterBase<_Item> {
390    public:
391      typedef _Item Item;
392      typedef _Reader Reader;
393      typedef typename Reader::Value Value;
394      typedef std::map<Value, Item> Inverse;
395
396      Reader reader;
397
398      SkipReaderInverter(const Reader& _reader)
399        : reader(_reader) {}
400
401      virtual ~SkipReaderInverter() {}
402
403      virtual void read(std::istream& is, const Item& item) {
404        Value value;
405        reader.read(is, value);
406        typename Inverse::iterator it = inverse.find(value);
407        if (it == inverse.end()) {
408          inverse.insert(std::make_pair(value, item));
409        } else {
410          throw DataFormatError("Multiple ID occurence error");
411        }
412      }
413
414      virtual Item read(std::istream& is) const {
415        Value value;
416        reader.read(is, value);
417        typename Inverse::const_iterator it = inverse.find(value);
418        if (it != inverse.end()) {
419          return it->second;
420        } else {
421          throw DataFormatError("Invalid ID error");
422        }
423      }
424
425    private:
426      Inverse inverse;
427    };
428
429    // Readers
430
431    template <typename _Item>   
432    class ReaderBase {
433    public:
434      typedef _Item Item;
435
436      virtual ~ReaderBase() {}
437
438      virtual void read(std::istream& is, const Item& item) = 0;
439      virtual InverterBase<_Item>* getInverter() = 0;
440    };
441
442    template <typename _Item, typename _Map, typename _Reader>
443    class MapReader : public ReaderBase<_Item> {
444    public:
445      typedef _Map Map;
446      typedef _Reader Reader;
447      typedef typename Reader::Value Value;
448      typedef _Item Item;
449     
450      Map& map;
451      Reader reader;
452
453      MapReader(Map& _map, const Reader& _reader)
454        : map(_map), reader(_reader) {}
455
456      virtual ~MapReader() {}
457
458      virtual void read(std::istream& is, const Item& item) {
459        Value value;
460        reader.read(is, value);
461        map.set(item, value);
462      }
463
464      virtual InverterBase<_Item>* getInverter() {
465        return new MapReaderInverter<Item, Map, Reader>(map, reader);
466      }
467    };
468
469
470    template <typename _Item, typename _Reader>
471    class SkipReader : public ReaderBase<_Item> {
472    public:
473      typedef _Reader Reader;
474      typedef typename Reader::Value Value;
475      typedef _Item Item;
476
477      Reader reader;
478      SkipReader(const Reader& _reader) : reader(_reader) {}
479
480      virtual ~SkipReader() {}
481
482      virtual void read(std::istream& is, const Item&) {
483        Value value;
484        reader.read(is, value);
485      }     
486
487      virtual InverterBase<Item>* getInverter() {
488        return new SkipReaderInverter<Item, Reader>(reader);
489      }
490    };
491
492    template <typename _Item>
493    class IdReaderBase {
494    public:
495      typedef _Item Item;
496      virtual Item read(std::istream& is) const = 0;
497    };
498
499    template <typename _Item, typename _BoxedIdReader>
500    class IdReader : public IdReaderBase<_Item> {
501    public:
502      typedef _Item Item;
503      typedef _BoxedIdReader BoxedIdReader;
504     
505      const BoxedIdReader& boxedIdReader;
506
507      IdReader(const BoxedIdReader& _boxedIdReader)
508        : boxedIdReader(_boxedIdReader) {}
509
510      virtual Item read(std::istream& is) const {
511        return boxedIdReader.readId(is);
512      }
513    };
514
515    class ValueReaderBase {
516    public:
517      virtual void read(std::istream&) {};
518    };
519
520    template <typename _Value, typename _Reader>
521    class ValueReader : public ValueReaderBase {
522    public:
523      typedef _Value Value;
524      typedef _Reader Reader;
525
526      ValueReader(Value& _value, const Reader& _reader)
527        : value(_value), reader(_reader) {}
528
529      virtual void read(std::istream& is) {
530        reader.read(is, value);
531      }
532    private:
533      Value& value;
534      Reader reader;
535    };
536   
537  };
538
539  /// \ingroup io_group
540  /// \brief SectionReader for reading a graph's nodeset.
541  ///
542  /// The lemon format can store multiple graph nodesets with several maps.
543  /// The nodeset section's header line is \c \@nodeset \c nodeset_id, but the
544  /// \c nodeset_id may be empty.
545  ///
546  /// The first line of the section contains the names of the maps separated
547  /// with white spaces. Each next lines describes a node in the nodeset, and
548  /// contains the mapped values for each map.
549  ///
550  /// If the nodeset contains an \c "id" named map then it will be regarded
551  /// as id map. This map should contain only unique values and when the
552  /// \c readId() member will read a value from the given stream it will
553  /// give back that node which is mapped to this value.
554  ///
555  /// \relates LemonReader
556  template <typename _Graph, typename _Traits = DefaultReaderTraits>
557  class NodeSetReader : public CommonSectionReaderBase {
558    typedef CommonSectionReaderBase Parent;
559  public:
560
561    typedef _Graph Graph;
562    typedef _Traits Traits;
563    typedef typename Graph::Node Item;
564    typedef typename Traits::Skipper DefaultSkipper;
565
566    /// \brief Constructor.
567    ///
568    /// Constructor for NodeSetReader. It creates the NodeSetReader and
569    /// attach it into the given LemonReader. The nodeset reader will
570    /// add the readed nodes to the given Graph. The reader will read
571    /// the section when the \c section_id and the \c _id are the same.
572    NodeSetReader(LemonReader& _reader, Graph& _graph,
573                  const std::string& _id = std::string(),
574                  const DefaultSkipper& _skipper = DefaultSkipper())
575      : Parent(_reader), graph(_graph), id(_id), skipper(_skipper) {}
576
577
578    /// \brief Destructor.
579    ///
580    /// Destructor for NodeSetReader.
581    virtual ~NodeSetReader() {
582      for (typename MapReaders::iterator it = readers.begin();
583           it != readers.end(); ++it) {
584        delete it->second;
585      }
586    }
587
588  private:
589    NodeSetReader(const NodeSetReader&);
590    void operator=(const NodeSetReader&);
591 
592  public:
593
594    /// \brief Add a new node map reader command for the reader.
595    ///
596    /// Add a new node map reader command for the reader.
597    template <typename Map>
598    NodeSetReader& readMap(std::string name, Map& map) {
599      return readMap<typename Traits::
600        template Reader<typename Map::Value>, Map>(name, map);
601    }
602
603    /// \brief Add a new node map reader command for the reader.
604    ///
605    /// Add a new node map reader command for the reader.
606    template <typename Reader, typename Map>
607    NodeSetReader& readMap(std::string name, Map& map,
608                             const Reader& reader = Reader()) {
609      if (readers.find(name) != readers.end()) {
610        ErrorMessage msg;
611        msg << "Multiple read rule for node map: " << name;
612        throw IOParameterError(msg.message());
613      }
614      readers.insert(
615        make_pair(name, new MapReader<Item, Map, Reader>(map, reader)));
616      return *this;
617    }
618
619    /// \brief Add a new node map skipper command for the reader.
620    ///
621    /// Add a new node map skipper command for the reader.
622    template <typename Reader>
623    NodeSetReader& skipMap(std::string name,
624                           const Reader& reader = Reader()) {
625      if (readers.find(name) != readers.end()) {
626        ErrorMessage msg;
627        msg << "Multiple read rule for node map: " << name;
628        throw IOParameterError(msg.message());
629      }
630      readers.insert(make_pair(name, new SkipReader<Item, Reader>(reader)));
631      return *this;
632    }
633
634  protected:
635
636    /// \brief Gives back true when the SectionReader can process
637    /// the section with the given header line.
638    ///
639    /// It gives back true when the header line starts with \c @nodeset,
640    /// and the header line's id and the nodeset's id are the same.
641    virtual bool header(const std::string& line) {
642      std::istringstream ls(line);
643      std::string command;
644      std::string name;
645      ls >> command >> name;
646      return command == "@nodeset" && name == id;
647    }
648
649    /// \brief Reader function of the section.
650    ///
651    /// It reads the content of the section.
652    virtual void read(std::istream& is) {
653      std::vector<ReaderBase<Item>* > index;
654      std::string line;
655
656      getline(is, line);
657      std::istringstream ls(line);     
658      while (ls >> id) {
659        typename MapReaders::iterator it = readers.find(id);
660        if (it != readers.end()) {
661          index.push_back(it->second);
662        } else {
663          index.push_back(&skipper);
664        }
665        if (id == "id" && inverter.get() == 0) {
666          inverter.reset(index.back()->getInverter());
667          index.back() = inverter.get();
668        }
669      }
670      while (getline(is, line)) {       
671        typename Graph::Node node = graph.addNode();
672        std::istringstream ls(line);
673        for (int i = 0; i < (int)index.size(); ++i) {
674          index[i]->read(ls, node);
675        }
676      }
677    }
678
679  public:
680
681    /// \brief Returns true if the nodeset can give back the node by its id.
682    ///
683    /// Returns true if the nodeset can give back the node by its id.
684    /// It is possible only if an "id" named map was read.
685    bool isIdReader() const {
686      return inverter.get() != 0;
687    }
688
689    /// \brief Gives back the node by its id.
690    ///
691    /// It reads an id from the stream and gives back which node belongs to
692    /// it. It is possible only if there was read an "id" named map.
693    typename Graph::Node readId(std::istream& is) const {
694      return inverter->read(is);
695    }
696
697  private:
698
699    typedef std::map<std::string, ReaderBase<Item>*> MapReaders;
700    MapReaders readers;
701   
702    Graph& graph;   
703    std::string id;
704    SkipReader<Item, DefaultSkipper> skipper;
705
706    std::auto_ptr<InverterBase<Item> > inverter;
707  };
708
709  /// \ingroup io_group
710  /// \brief SectionReader for reading a graph's edgeset.
711  ///
712  /// The lemon format can store multiple graph edgesets with several maps.
713  /// The edgeset section's header line is \c \@edgeset \c edgeset_id, but the
714  /// \c edgeset_id may be empty.
715  ///
716  /// The first line of the section contains the names of the maps separated
717  /// with white spaces. Each next lines describes a node in the nodeset. The
718  /// line contains the two nodes' id and the mapped values for each map.
719  ///
720  /// If the edgeset contains an \c "id" named map then it will be regarded
721  /// as id map. This map should contain only unique values and when the
722  /// \c readId() member will read a value from the given stream it will
723  /// give back that edge which is mapped to this value.
724  ///
725  /// The edgeset reader needs a node id reader to identify which nodes
726  /// have to be connected. If a NodeSetReader reads an "id" named map,
727  /// it will be able to resolve the nodes by ids.
728  ///
729  /// \relates LemonReader
730  template <typename _Graph, typename _Traits = DefaultReaderTraits>
731  class EdgeSetReader : public CommonSectionReaderBase {
732    typedef CommonSectionReaderBase Parent;
733  public:
734
735    typedef _Graph Graph;
736    typedef _Traits Traits;
737    typedef typename Graph::Edge Item;
738    typedef typename Traits::Skipper DefaultSkipper;
739
740    /// \brief Constructor.
741    ///
742    /// Constructor for EdgeSetReader. It creates the EdgeSetReader and
743    /// attach it into the given LemonReader. The edgeset reader will
744    /// add the readed edges to the given Graph. It will use the given
745    /// node id reader to read the source and target nodes of the edges.
746    /// The reader will read the section only if the \c _id and the
747    /// \c edgset_id are the same.
748    template <typename NodeIdReader>
749    EdgeSetReader(LemonReader& _reader, Graph& _graph,
750                  const NodeIdReader& _nodeIdReader,
751                  const std::string& _id = std::string(),
752                  const DefaultSkipper& _skipper = DefaultSkipper())
753      : Parent(_reader), graph(_graph), id(_id), skipper(_skipper),
754        nodeIdReader(new IdReader<typename Graph::Node, NodeIdReader>
755                     (_nodeIdReader)) {}
756
757    /// \brief Destructor.
758    ///
759    /// Destructor for EdgeSetReader.
760    virtual ~EdgeSetReader() {
761      for (typename MapReaders::iterator it = readers.begin();
762           it != readers.end(); ++it) {
763        delete it->second;
764      }
765    }
766
767  private:
768    EdgeSetReader(const EdgeSetReader&);
769    void operator=(const EdgeSetReader&);
770
771  public:
772
773    /// \brief Add a new edge map reader command for the reader.
774    ///
775    /// Add a new edge map reader command for the reader.
776    template <typename Map>
777    EdgeSetReader& readMap(std::string name, Map& map) {
778      return readMap<typename Traits::
779        template Reader<typename Map::Value>, Map>(name, map);
780    }
781
782    /// \brief Add a new edge map reader command for the reader.
783    ///
784    /// Add a new edge map reader command for the reader.
785    template <typename Reader, typename Map>
786    EdgeSetReader& readMap(std::string name, Map& map,
787                             const Reader& reader = Reader()) {
788      if (readers.find(name) != readers.end()) {
789        ErrorMessage msg;
790        msg << "Multiple read rule for edge map: " << name;
791        throw IOParameterError(msg.message());
792      }
793      readers.insert(
794        make_pair(name, new MapReader<Item, Map, Reader>(map, reader)));
795      return *this;
796    }
797
798    /// \brief Add a new edge map skipper command for the reader.
799    ///
800    /// Add a new edge map skipper command for the reader.
801    template <typename Reader>
802    EdgeSetReader& skipMap(std::string name,
803                           const Reader& reader = Reader()) {
804      if (readers.find(name) != readers.end()) {
805        ErrorMessage msg;
806        msg << "Multiple read rule for node map: " << name;
807        throw IOParameterError(msg.message());
808      }
809      readers.insert(make_pair(name, new SkipReader<Item, Reader>(reader)));
810      return *this;
811    }
812
813  protected:
814
815    /// \brief Gives back true when the SectionReader can process
816    /// the section with the given header line.
817    ///
818    /// It gives back true when the header line starts with \c @edgeset,
819    /// and the header line's id and the edgeset's id are the same.
820    virtual bool header(const std::string& line) {
821      std::istringstream ls(line);
822      std::string command;
823      std::string name;
824      ls >> command >> name;
825      return command == "@edgeset" && name == id;
826    }
827
828    /// \brief Reader function of the section.
829    ///
830    /// It reads the content of the section.
831    virtual void read(std::istream& is) {
832      std::vector<ReaderBase<Item>* > index;
833      std::string line;
834
835      getline(is, line);
836      std::istringstream ls(line);     
837      while (ls >> id) {
838        typename MapReaders::iterator it = readers.find(id);
839        if (it != readers.end()) {
840          index.push_back(it->second);
841        } else {
842          index.push_back(&skipper);
843        }
844        if (id == "id" && inverter.get() == 0) {
845          inverter.reset(index.back()->getInverter());
846          index.back() = inverter.get();
847        }
848      }
849      while (getline(is, line)) {       
850        std::istringstream ls(line);
851        typename Graph::Node from = nodeIdReader->read(ls);
852        typename Graph::Node to = nodeIdReader->read(ls);
853        typename Graph::Edge edge = graph.addEdge(from, to);
854        for (int i = 0; i < (int)index.size(); ++i) {
855          index[i]->read(ls, edge);
856        }
857      }
858    }
859
860  public:
861
862    /// \brief Returns true if the edgeset can give back the edge by its id.
863    ///
864    /// Returns true if the edgeset can give back the edge by its id.
865    /// It is possible only if an "id" named map was read.
866    bool isIdReader() const {
867      return inverter.get() != 0;
868    }
869
870    /// \brief Gives back the edge by its id.
871    ///
872    /// It reads an id from the stream and gives back which edge belongs to
873    /// it. It is possible only if there was read an "id" named map.
874    typename Graph::Edge readId(std::istream& is) const {
875      return inverter->read(is);
876    }
877
878  private:
879
880    typedef std::map<std::string, ReaderBase<Item>*> MapReaders;
881    MapReaders readers;
882   
883    Graph& graph;   
884    std::string id;
885    SkipReader<Item, DefaultSkipper> skipper;
886
887    std::auto_ptr<InverterBase<Item> > inverter;
888    std::auto_ptr<IdReaderBase<typename Graph::Node> > nodeIdReader;
889  };
890
891  /// \ingroup io_group
892  /// \brief SectionReader for reading labeled nodes.
893  ///
894  /// The nodes section's header line is \c \@nodes \c nodes_id, but the
895  /// \c nodes_id may be empty.
896  ///
897  /// Each line in the section contains the name of the node
898  /// and then the node id.
899  ///
900  /// \relates LemonReader
901  template <typename _Graph>
902  class NodeReader : public CommonSectionReaderBase {
903    typedef CommonSectionReaderBase Parent;
904    typedef _Graph Graph;
905    typedef typename Graph::Node Item;
906  public:
907   
908    /// \brief Constructor.
909    ///
910    /// Constructor for NodeReader. It creates the NodeReader and
911    /// attach it into the given LemonReader. It will use the given
912    /// node id reader to give back the nodes. The reader will read the
913    /// section only if the \c _id and the \c nodes_id are the same.
914    template <typename _IdReader>
915    NodeReader(LemonReader& _reader, const _IdReader& _idReader,
916               const std::string& _id = std::string())
917      : Parent(_reader), id(_id),
918        idReader(new IdReader<typename Graph::Node, _IdReader>(_idReader)) {}
919
920    /// \brief Destructor.
921    ///
922    /// Destructor for NodeReader.
923    virtual ~NodeReader() {}
924
925  private:
926    NodeReader(const NodeReader&);
927    void operator=(const NodeReader&);
928
929  public:
930
931    /// \brief Add a node reader command for the NodeReader.
932    ///
933    /// Add a node reader command for the NodeReader.
934    void readNode(const std::string& name, Item& item) {
935      if (readers.find(name) != readers.end()) {
936        ErrorMessage msg;
937        msg << "Multiple read rule for node: " << name;
938        throw IOParameterError(msg.message());
939      }
940      readers.insert(make_pair(name, &item));
941    }
942
943  protected:
944
945    /// \brief Gives back true when the SectionReader can process
946    /// the section with the given header line.
947    ///
948    /// It gives back true when the header line start with \c @nodes,
949    /// and the header line's id and the reader's id are the same.
950    virtual bool header(const std::string& line) {
951      std::istringstream ls(line);
952      std::string command;
953      std::string name;
954      ls >> command >> name;
955      return command == "@nodes" && name == id;
956    }
957
958    /// \brief Reader function of the section.
959    ///
960    /// It reads the content of the section.
961    virtual void read(std::istream& is) {
962      std::string line;
963      while (getline(is, line)) {
964        std::istringstream ls(line);
965        std::string id;
966        ls >> id;
967        typename ItemReaders::iterator it = readers.find(id);
968        if (it != readers.end()) {
969          *(it->second) = idReader->read(ls);
970        }       
971      }
972    }
973   
974  private:
975
976    std::string id;
977
978    typedef std::map<std::string, Item*> ItemReaders;
979    ItemReaders readers;
980    std::auto_ptr<IdReaderBase<Item> > idReader;
981  };
982
983  /// \ingroup io_group
984  /// \brief SectionReader for reading labeled edges.
985  ///
986  /// The edges section's header line is \c \@edges \c edges_id, but the
987  /// \c edges_id may be empty.
988  ///
989  /// Each line in the section contains the name of the edge
990  /// and then the edge id.
991  ///
992  /// \relates LemonReader
993  template <typename _Graph>
994  class EdgeReader : public CommonSectionReaderBase {
995    typedef CommonSectionReaderBase Parent;
996    typedef _Graph Graph;
997    typedef typename Graph::Edge Item;
998  public:
999   
1000    /// \brief Constructor.
1001    ///
1002    /// Constructor for EdgeReader. It creates the EdgeReader and
1003    /// attach it into the given LemonReader. It will use the given
1004    /// edge id reader to give back the edges. The reader will read the
1005    /// section only if the \c _id and the \c nodes_id are the same.
1006    template <typename _IdReader>
1007    EdgeReader(LemonReader& _reader, const _IdReader& _idReader,
1008               const std::string& _id = std::string())
1009      : Parent(_reader), id(_id),
1010        idReader(new IdReader<typename Graph::Edge, _IdReader>(_idReader)) {}
1011
1012    /// \brief Destructor.
1013    ///
1014    /// Destructor for EdgeReader.
1015    virtual ~EdgeReader() {}
1016  private:
1017    EdgeReader(const EdgeReader&);
1018    void operator=(const EdgeReader&);
1019
1020  public:
1021
1022    /// \brief Add an edge reader command for the EdgeReader.
1023    ///
1024    /// Add an edge reader command for the EdgeReader.
1025    void readEdge(const std::string& name, Item& item) {
1026      if (readers.find(name) != readers.end()) {
1027        ErrorMessage msg;
1028        msg << "Multiple read rule for edge: " << name;
1029        throw IOParameterError(msg.message());
1030      }
1031      readers.insert(make_pair(name, &item));
1032    }
1033
1034  protected:
1035
1036    /// \brief Gives back true when the SectionReader can process
1037    /// the section with the given header line.
1038    ///
1039    /// It gives back true when the header line start with \c @edges,
1040    /// and the header line's id and the reader's id are the same.
1041    virtual bool header(const std::string& line) {
1042      std::istringstream ls(line);
1043      std::string command;
1044      std::string name;
1045      ls >> command >> name;
1046      return command == "@edges" && name == id;
1047    }
1048
1049    /// \brief Reader function of the section.
1050    ///
1051    /// It reads the content of the section.
1052    virtual void read(std::istream& is) {
1053      std::string line;
1054      while (getline(is, line)) {
1055        std::istringstream ls(line);
1056        std::string id;
1057        ls >> id;
1058        typename ItemReaders::iterator it = readers.find(id);
1059        if (it != readers.end()) {
1060          *(it->second) = idReader->read(ls);
1061        }       
1062      }
1063    }
1064   
1065  private:
1066
1067    std::string id;
1068
1069    typedef std::map<std::string, Item*> ItemReaders;
1070    ItemReaders readers;
1071    std::auto_ptr<IdReaderBase<Item> > idReader;
1072  };
1073
1074  /// \ingroup io_group
1075  /// \brief SectionReader for attributes.
1076  ///
1077  /// The lemon format can store multiple attribute set. Each set has
1078  /// the header line \c \@attributes \c attributeset_id, but the
1079  /// attributeset_id may be empty.
1080  ///
1081  /// The attributeset section contains several lines. Each of them starts
1082  /// with an attribute and then a the value for the id.
1083  ///
1084  /// \relates LemonReader
1085  template <typename _Traits = DefaultReaderTraits>
1086  class AttributeReader : public CommonSectionReaderBase {
1087    typedef CommonSectionReaderBase Parent;
1088    typedef _Traits Traits;
1089  public:
1090    /// \brief Constructor.
1091    ///
1092    /// Constructor for AttributeReader. It creates the AttributeReader and
1093    /// attach it into the given LemonReader. The reader process a section
1094    /// only if the \c section_id and the \c _id are the same.
1095    AttributeReader(LemonReader& _reader,
1096                    const std::string& _id = std::string())
1097      : Parent(_reader), id(_id) {}
1098
1099    /// \brief Destructor.
1100    ///
1101    /// Destructor for AttributeReader.
1102    virtual ~AttributeReader() {
1103      for (typename Readers::iterator it = readers.begin();
1104           it != readers.end(); ++it) {
1105        delete it->second;
1106      }
1107    }
1108
1109  private:
1110    AttributeReader(const AttributeReader&);
1111    void operator=(AttributeReader&);
1112
1113  public:
1114    /// \brief Add an attribute reader command for the reader.
1115    ///
1116    /// Add an attribute reader command for the reader.
1117    template <typename Value>
1118    AttributeReader& readAttribute(const std::string& id, Value& value) {
1119      return readAttribute<typename Traits::template Reader<Value> >
1120        (id, value);
1121    }
1122
1123    /// \brief Add an attribute reader command for the reader.
1124    ///
1125    /// Add an attribute reader command for the reader.
1126    template <typename Reader, typename Value>
1127    AttributeReader& readAttribute(const std::string& name, Value& value,
1128                                   const Reader& reader = Reader()) {
1129      if (readers.find(name) != readers.end()) {
1130        ErrorMessage msg;
1131        msg << "Multiple read rule for attribute: " << name;
1132        throw IOParameterError(msg.message());
1133      }
1134      readers.insert(make_pair(name, new ValueReader<Value, Reader>
1135                               (value, reader)));
1136      return *this;
1137    }
1138
1139  protected:
1140
1141    /// \brief Gives back true when the SectionReader can process
1142    /// the section with the given header line.
1143    ///
1144    /// It gives back true when the header line start with \c @attributes,
1145    /// and the header line's id and the attributeset's id are the same.
1146    bool header(const std::string& line) {
1147      std::istringstream ls(line);
1148      std::string command;
1149      std::string name;
1150      ls >> command >> name;
1151      return command == "@attributes" && name == id;
1152    }
1153
1154    /// \brief Reader function of the section.
1155    ///
1156    /// It reads the content of the section.
1157    void read(std::istream& is) {
1158      std::string line;
1159      while (getline(is, line)) {
1160        std::istringstream ls(line);
1161        std::string id;
1162        ls >> id;
1163        typename Readers::iterator it = readers.find(id);
1164        if (it != readers.end()) {
1165          it->second->read(ls);
1166        }
1167      }
1168    }   
1169
1170  private:
1171    std::string id;
1172
1173    typedef std::map<std::string, ValueReaderBase*> Readers;
1174    Readers readers; 
1175  };
1176
1177
1178}
1179#endif
Note: See TracBrowser for help on using the repository browser.