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