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