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