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