lemon/bits/item_reader.h
author deba
Fri, 24 Feb 2006 11:13:09 +0000
changeset 1984 d4cbd10e1256
parent 1946 17eb3eaad9f8
child 2016 ecb067198349
permissions -rw-r--r--
Bug fix
deba@1408
     1
/* -*- C++ -*-
deba@1408
     2
 *
alpar@1956
     3
 * This file is a part of LEMON, a generic C++ optimization library
alpar@1956
     4
 *
alpar@1956
     5
 * Copyright (C) 2003-2006
alpar@1956
     6
 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
alpar@1956
     7
 * (Egervary Research Group on Combinatorial Optimization, EGRES).
deba@1408
     8
 *
deba@1408
     9
 * Permission to use, modify and distribute this software is granted
deba@1408
    10
 * provided that this copyright notice appears in all copies. For
deba@1408
    11
 * precise terms see the accompanying LICENSE file.
deba@1408
    12
 *
deba@1408
    13
 * This software is provided "AS IS" with no warranty of any kind,
deba@1408
    14
 * express or implied, and with no claim as to its suitability for any
deba@1408
    15
 * purpose.
deba@1408
    16
 *
deba@1408
    17
 */
deba@1408
    18
deba@1910
    19
/// @defgroin item_io Item Readers and Writers
alpar@1946
    20
/// @ingroup io_groin
deba@1415
    21
/// \brief Item Readers and Writers
deba@1415
    22
/// 
deba@1415
    23
/// The Input-Output classes can handle more data type by example
deba@1415
    24
/// as map or attribute value. Each of these should be written and
deba@1415
    25
/// read some way. The module make possible to do this.  
deba@1415
    26
alpar@1946
    27
/// \ingroup item_io
deba@1408
    28
/// \file
deba@1408
    29
/// \brief Item reader bits for lemon input.
deba@1408
    30
deba@1408
    31
#ifndef LEMON_BITS_ITEM_READER_H
deba@1408
    32
#define LEMON_BITS_ITEM_READER_H
deba@1408
    33
deba@1408
    34
#include <iostream>
deba@1408
    35
#include <string>
deba@1408
    36
deba@1408
    37
#include <vector>
deba@1408
    38
#include <deque>
deba@1408
    39
#include <list>
deba@1408
    40
#include <set>
deba@1408
    41
deba@1408
    42
namespace lemon {
deba@1408
    43
  
deba@1408
    44
  template <typename Value>
deba@1408
    45
  class DefaultReader;
deba@1408
    46
alpar@1946
    47
  /// \ingroup item_io
deba@1408
    48
  ///
deba@1408
    49
  /// \brief Reader class for quoted strings.
deba@1408
    50
  ///
deba@1408
    51
  /// Reader class for quoted strings. It can process the escape
deba@1408
    52
  /// sequences in the string.
deba@1408
    53
  ///
deba@1408
    54
  /// \author Balazs Dezso
deba@1408
    55
  class QuotedStringReader {
deba@1408
    56
  public:
deba@1408
    57
    /// \brief The value type of reader.
deba@1408
    58
    ///
deba@1408
    59
    /// The value type of reader.
deba@1408
    60
    typedef std::string Value;
deba@1408
    61
    
deba@1408
    62
    /// \brief Constructor for the reader.
deba@1408
    63
    ///
deba@1408
    64
    /// Constructor for the reader. If the given parameter is true
deba@1408
    65
    /// the reader processes the escape sequences.
deba@1408
    66
    QuotedStringReader(bool _escaped = true) 
deba@1408
    67
      : escaped(_escaped) {}
deba@1408
    68
    
deba@1408
    69
    /// \brief Reads a quoted string from the given stream.
deba@1408
    70
    ///
deba@1408
    71
    /// Reads a quoted string from the given stream.
deba@1408
    72
    void read(std::istream& is, std::string& value) const {
deba@1408
    73
      char c;
deba@1408
    74
      value.clear();
deba@1408
    75
      is >> std::ws;
deba@1408
    76
      if (!is.get(c) || c != '\"') 
deba@1408
    77
	throw DataFormatError("Quoted string format error");
deba@1408
    78
      while (is.get(c) && c != '\"') {
deba@1408
    79
	if (escaped && c == '\\') {
deba@1408
    80
	  value += readEscape(is);
deba@1408
    81
	} else {
deba@1408
    82
	  value += c;
deba@1408
    83
	}
deba@1408
    84
      }
deba@1408
    85
      if (!is) throw DataFormatError("Quoted string format error");
deba@1408
    86
    }
deba@1408
    87
deba@1408
    88
  private:
deba@1408
    89
    
deba@1408
    90
    static char readEscape(std::istream& is) {
deba@1408
    91
      char c;
deba@1408
    92
      switch (is.get(c), c) {
deba@1408
    93
      case '\\':
deba@1408
    94
	return '\\';
deba@1408
    95
      case '\"':
deba@1408
    96
	return '\"';
deba@1408
    97
      case '\'':
deba@1408
    98
	return '\'';
deba@1408
    99
      case '\?':
deba@1408
   100
	return '\?';
deba@1408
   101
      case 'a':
deba@1408
   102
	return '\a';
deba@1408
   103
      case 'b':
deba@1408
   104
	return '\b';
deba@1408
   105
      case 'f':
deba@1408
   106
	return '\f';
deba@1408
   107
      case 'n':
deba@1408
   108
	return '\n';
deba@1408
   109
      case 'r':
deba@1408
   110
	return '\r';
deba@1408
   111
      case 't':
deba@1408
   112
	return '\t';
deba@1408
   113
      case 'v':
deba@1408
   114
	return '\v';
deba@1408
   115
      case 'x':
deba@1408
   116
	{
deba@1408
   117
	  int code;
deba@1408
   118
	  if (!is.get(c) || !isHex(c)) 
deba@1408
   119
	    throw DataFormatError("Escape format error");
deba@1408
   120
	  else if (code = valueHex(c), !is.get(c) || !isHex(c)) is.putback(c);
deba@1408
   121
	  else code = code * 16 + valueHex(c);
deba@1408
   122
	  return code;
deba@1408
   123
	}
deba@1408
   124
      default:
deba@1408
   125
	{
deba@1408
   126
	  int code;
deba@1408
   127
	  if (!isOct(c)) 
deba@1408
   128
	    throw DataFormatError("Escape format error");
deba@1408
   129
	  else if (code = valueOct(c), !is.get(c) || !isOct(c)) 
deba@1408
   130
	    is.putback(c);
deba@1408
   131
	  else if (code = code * 8 + valueOct(c), !is.get(c) || !isOct(c)) 
deba@1408
   132
	    is.putback(c);
deba@1408
   133
	  else code = code * 8 + valueOct(c);
deba@1408
   134
	  return code;
deba@1408
   135
	}	      
deba@1408
   136
      } 
deba@1408
   137
    }
deba@1408
   138
deba@1408
   139
    static bool isOct(char c) {
deba@1408
   140
      return '0' <= c && c <='7'; 
deba@1408
   141
    }
deba@1408
   142
    
deba@1408
   143
    static int valueOct(char c) {
deba@1408
   144
      return c - '0';
deba@1408
   145
    }
deba@1408
   146
deba@1408
   147
   static bool isHex(char c) {
deba@1408
   148
      return ('0' <= c && c <= '9') || 
deba@1408
   149
	('a' <= c && c <= 'z') || 
deba@1408
   150
	('A' <= c && c <= 'Z'); 
deba@1408
   151
    }
deba@1408
   152
    
deba@1408
   153
    static int valueHex(char c) {
deba@1408
   154
      if ('0' <= c && c <= '9') return c - '0';
deba@1408
   155
      if ('a' <= c && c <= 'z') return c - 'a' + 10;
deba@1408
   156
      return c - 'A' + 10;
deba@1408
   157
    }
deba@1408
   158
deba@1408
   159
    bool escaped;
deba@1408
   160
  };
deba@1408
   161
alpar@1946
   162
  /// \ingroup item_io
deba@1408
   163
  /// \brief Reader for standard containers.
deba@1408
   164
  ///
deba@1408
   165
  /// Reader for back insertable standard containers. The representation
deba@1408
   166
  /// of the container is the values enumerated between an open and a
deba@1408
   167
  /// close parse. 
deba@1408
   168
  ///
deba@1408
   169
  /// \author Balazs Dezso
deba@1408
   170
  template <
deba@1408
   171
    typename _Container, 
deba@1408
   172
    typename _ItemReader = DefaultReader<typename _Container::value_type> 
deba@1408
   173
  >
deba@1408
   174
  class PushBackReader {
deba@1408
   175
  public:
deba@1408
   176
    typedef _Container Value;
deba@1408
   177
    typedef _ItemReader ItemReader;
deba@1408
   178
deba@1408
   179
  private:
deba@1408
   180
deba@1408
   181
    ItemReader item_reader;
deba@1408
   182
deba@1408
   183
  public:
deba@1408
   184
deba@1852
   185
    /// \brief Constructor for InsertReader
deba@1852
   186
    ///
deba@1852
   187
    /// Constructor for InsertReader
deba@1852
   188
    PushBackReader(const ItemReader& _item_reader = ItemReader())
deba@1852
   189
      : item_reader(_item_reader) {}
deba@1852
   190
deba@1408
   191
    /// \brief Reads the values into the container from the given stream.
deba@1408
   192
    ///
deba@1408
   193
    /// Reads the values into the container from the given stream.
deba@1408
   194
    void read(std::istream& is, Value& value) const {
deba@1408
   195
      char c;
deba@1408
   196
      if (!(is >> c) || c != '(') 
deba@1408
   197
	throw DataFormatError("PushBackReader format error");
deba@1408
   198
      while (is >> c && c != ')') {
deba@1408
   199
	is.putback(c);
deba@1408
   200
	typename ItemReader::Value item;
deba@1408
   201
	item_reader.read(is, item);
deba@1408
   202
	value.push_back(item);
deba@1408
   203
      }
deba@1408
   204
      if (!is) throw DataFormatError("PushBackReader format error");
deba@1408
   205
    }
deba@1408
   206
deba@1408
   207
  };
deba@1408
   208
alpar@1946
   209
  /// \ingroup item_io
deba@1408
   210
  ///
deba@1408
   211
  /// \brief Reader for standard containers.
deba@1408
   212
  ///
deba@1408
   213
  /// Reader for insertable standard containers. The representation
deba@1408
   214
  /// of the container is the values enumerated between an open and a
deba@1408
   215
  /// close parse. 
deba@1408
   216
  ///
deba@1408
   217
  /// \author Balazs Dezso
deba@1408
   218
  template <
deba@1408
   219
    typename _Container, 
deba@1408
   220
    typename _ItemReader = DefaultReader<typename _Container::value_type> 
deba@1408
   221
  >
deba@1408
   222
  class InsertReader {
deba@1408
   223
  public:
deba@1408
   224
    typedef _Container Value;
deba@1408
   225
    typedef _ItemReader ItemReader;
deba@1408
   226
deba@1408
   227
  private:
deba@1408
   228
deba@1408
   229
    ItemReader item_reader;
deba@1408
   230
deba@1408
   231
  public:
deba@1408
   232
deba@1852
   233
    /// \brief Constructor for InsertReader
deba@1852
   234
    ///
deba@1852
   235
    /// Constructor for InsertReader
deba@1852
   236
    InsertReader(const ItemReader& _item_reader = ItemReader())
deba@1852
   237
      : item_reader(_item_reader) {}
deba@1852
   238
deba@1408
   239
    /// \brief Reads the values into the container from the given stream.
deba@1408
   240
    ///
deba@1408
   241
    /// Reads the values into the container from the given stream.
deba@1408
   242
    void read(std::istream& is, Value& value) const {
deba@1408
   243
      char c;
deba@1408
   244
      if (!(is >> c) || c != '(') 
deba@1408
   245
	throw DataFormatError("InsertReader format error");
deba@1408
   246
      while (is >> c && c != ')') {
deba@1408
   247
	is.putback(c);
deba@1408
   248
	typename ItemReader::Value item;
deba@1408
   249
	item_reader.read(is, item);
deba@1408
   250
	value.insert(item);
deba@1408
   251
      }
deba@1408
   252
      if (!is) throw DataFormatError("PushBackReader format error");
deba@1408
   253
    }
deba@1408
   254
deba@1408
   255
  };
deba@1408
   256
alpar@1946
   257
  /// \ingroup item_io
deba@1408
   258
  /// \brief Reader for parsed string.
deba@1408
   259
  ///
deba@1744
   260
  /// Reader for parsed strings. You can define the open and close
deba@1744
   261
  /// parse characters. It reads from the input a character sequence
deba@1744
   262
  /// which is right parsed.
deba@1408
   263
  ///
deba@1408
   264
  /// \author Balazs Dezso
deba@1408
   265
  class ParsedStringReader {
deba@1408
   266
  public:
deba@1408
   267
    typedef std::string Value;
deba@1408
   268
deba@1408
   269
    /// \brief Constructor.
deba@1408
   270
    ///
deba@1408
   271
    /// Constructor for ParsedStringReader. You can give as parameter
deba@1408
   272
    /// the open and close parse characters.
deba@1408
   273
    ParsedStringReader(char _open = '(', char _close = ')')
deba@1408
   274
      : open(_open), close(_close) {}
deba@1408
   275
    
deba@1408
   276
    
deba@1408
   277
    /// \brief Reads the parsed string from the given stream.
deba@1408
   278
    ///
deba@1408
   279
    /// Reads the parsed string from the given stream.
deba@1408
   280
    void read(std::istream& is, Value& value) const {
deba@1408
   281
      char c;
deba@1408
   282
      if (!(is >> c) || c != open) {
deba@1408
   283
	throw DataFormatError("ParsedStringReader format error");
deba@1408
   284
      }
deba@1408
   285
      value += c;
deba@1408
   286
      int counter = 1;
deba@1408
   287
      while (counter > 0 && is >> c) {
deba@1408
   288
	if (c == close) {
deba@1408
   289
	  --counter;
deba@1408
   290
	} else if (c == open) {
deba@1408
   291
	  ++counter;
deba@1408
   292
	}
deba@1408
   293
	value += c;
deba@1408
   294
      }
deba@1408
   295
      if (!is) {
deba@1408
   296
	throw DataFormatError("ParsedStrinReader format error");
deba@1408
   297
      }
deba@1408
   298
    }
deba@1408
   299
deba@1408
   300
  private:
deba@1408
   301
    char open, close;
deba@1408
   302
deba@1408
   303
  };
deba@1408
   304
alpar@1946
   305
  /// \ingroup item_io
deba@1408
   306
  /// \brief Reader for read the whole line.
deba@1408
   307
  ///
deba@1408
   308
  /// Reader for read the whole line.
deba@1408
   309
  ///
deba@1408
   310
  /// \author Balazs Dezso
deba@1408
   311
  class LineReader {
deba@1408
   312
  public:
deba@1408
   313
    typedef std::string Value;
deba@1408
   314
deba@1408
   315
    /// \brief Constructor.
deba@1408
   316
    ///
deba@1408
   317
    /// Constructor for the LineReader. If the given parameter is
deba@1408
   318
    /// true then the spaces before the first not space character are
deba@1408
   319
    /// skipped.
deba@1408
   320
    LineReader(bool _skipSpaces = true) : skipSpaces(_skipSpaces) {}
deba@1408
   321
    
deba@1408
   322
    /// \brief Reads the line from the given stream.
deba@1408
   323
    ///
deba@1408
   324
    /// Reads the line from the given stream.
deba@1852
   325
    void read(std::istream& is, Value& value) const {
deba@1408
   326
      if (skipSpaces) is >> std::ws;
deba@1408
   327
      if (!getline(is, value)) {
deba@1852
   328
	throw DataFormatError("LineReader format error");
deba@1408
   329
      }
deba@1408
   330
    }
deba@1408
   331
  private:
deba@1408
   332
    bool skipSpaces;
deba@1408
   333
  };
deba@1408
   334
alpar@1946
   335
  /// \ingroup item_io
deba@1852
   336
  /// \brief Reader for std::pair.
deba@1852
   337
  ///
deba@1852
   338
  /// Reader for std::pair.
deba@1852
   339
  ///
deba@1852
   340
  /// \author Balazs Dezso
deba@1852
   341
  template <typename _Pair, 
deba@1852
   342
	    typename _FirstReader = 
deba@1852
   343
	    DefaultReader<typename _Pair::first_type>,
deba@1852
   344
	    typename _SecondReader = 
deba@1852
   345
	    DefaultReader<typename _Pair::second_type> >
deba@1852
   346
  class PairReader {
deba@1852
   347
  public:
deba@1852
   348
    typedef _Pair Value;
deba@1852
   349
deba@1852
   350
    typedef _FirstReader FirstReader;
deba@1852
   351
    typedef _SecondReader SecondReader;
deba@1852
   352
deba@1852
   353
  private:
deba@1852
   354
deba@1852
   355
    FirstReader first_reader;
deba@1852
   356
    SecondReader second_reader;
deba@1852
   357
deba@1852
   358
  public:
deba@1852
   359
    
deba@1852
   360
    /// \brief Constructor.
deba@1852
   361
    ///
deba@1852
   362
    /// Constructor for the PairReader.
deba@1852
   363
    PairReader(const FirstReader& _first_reader = FirstReader(), 
deba@1852
   364
	       const SecondReader& _second_reader = SecondReader()) 
deba@1852
   365
      : first_reader(_first_reader), second_reader(_second_reader) {}
deba@1852
   366
    
deba@1852
   367
    /// \brief Reads the pair from the given stream.
deba@1852
   368
    ///
deba@1852
   369
    /// Reads the pair from the given stream.
deba@1852
   370
    void read(std::istream& is, Value& value) const {
deba@1852
   371
      char c;
deba@1852
   372
      if (!(is >> c) || c != '(') {
deba@1852
   373
	throw DataFormatError("PairReader format error");
deba@1852
   374
      }
deba@1852
   375
      first_reader.read(is, value.first);
deba@1852
   376
      if (!(is >> c) || c != '=') {
deba@1852
   377
	throw DataFormatError("PairReader format error");
deba@1852
   378
      }
deba@1852
   379
      if (!(is >> c) || c != '>') {
deba@1852
   380
	throw DataFormatError("PairReader format error");
deba@1852
   381
      }
deba@1852
   382
      second_reader.read(is, value.second);
deba@1852
   383
      if (!(is >> c) || c != ')') {
deba@1852
   384
	throw DataFormatError("PairReader format error");
deba@1852
   385
      }
deba@1852
   386
    }
deba@1852
   387
  };
deba@1852
   388
alpar@1946
   389
  /// \ingroup item_io
deba@1408
   390
  /// 
deba@1408
   391
  /// \brief The default item reader template class.
deba@1408
   392
  ///
deba@1408
   393
  /// The default item reader template class. If some section reader
deba@1408
   394
  /// needs to read a value from a stream it will give the default way for it.
deba@1408
   395
  ///
deba@1408
   396
  /// \author Balazs Dezso
deba@1408
   397
  template <typename _Value>
deba@1408
   398
  class DefaultReader {
deba@1408
   399
  public:
deba@1408
   400
    /// The value type.
deba@1408
   401
    typedef _Value Value;
deba@1408
   402
    /// \brief Reads a value from the given stream.
deba@1408
   403
    ///
deba@1408
   404
    /// Reads a value from the given stream.
deba@1408
   405
    void read(std::istream& is, Value& value) const {
deba@1408
   406
      if (!(is >> value)) 
deba@1408
   407
	throw DataFormatError("DefaultReader format error");
deba@1408
   408
    }
deba@1408
   409
  };
deba@1408
   410
deba@1427
   411
  template <>
deba@1427
   412
  class DefaultReader<std::string> {
deba@1427
   413
  public:
deba@1427
   414
    typedef std::string Value;
deba@1427
   415
    
deba@1427
   416
    void read(std::istream& is, Value& value) const {
deba@1427
   417
      char c;
deba@1429
   418
      if (!(is >> std::ws >> c)) return;
deba@1427
   419
      is.putback(c);
deba@1427
   420
      switch (c) {
deba@1427
   421
      case '\"':
deba@1427
   422
	QuotedStringReader().read(is, value);
deba@1427
   423
	break;
deba@1427
   424
      case '(':
deba@1427
   425
	ParsedStringReader().read(is, value);
deba@1427
   426
	break;
deba@1744
   427
      case '[':
deba@1744
   428
	ParsedStringReader('[', ']').read(is, value);
deba@1744
   429
	break;
deba@1744
   430
      case '/':
deba@1744
   431
	ParsedStringReader('/', '/').read(is, value);
deba@1744
   432
	break;
deba@1427
   433
      default:
deba@1744
   434
	if (!(is >> value)) 
deba@1744
   435
	  throw DataFormatError("DefaultReader format error");
deba@1427
   436
	break;
deba@1427
   437
      }
deba@1427
   438
    }
deba@1427
   439
    
deba@1427
   440
  };
deba@1427
   441
deba@1408
   442
  template <typename Item>
deba@1408
   443
  class DefaultReader<std::vector<Item> > 
deba@1408
   444
    : public PushBackReader<std::vector<Item> > {};
deba@1408
   445
deba@1408
   446
  template <typename Item>
deba@1408
   447
  class DefaultReader<std::deque<Item> > 
deba@1408
   448
    : public PushBackReader<std::deque<Item> > {};
deba@1408
   449
deba@1408
   450
  template <typename Item>
deba@1408
   451
  class DefaultReader<std::list<Item> > 
deba@1408
   452
    : public PushBackReader<std::list<Item> > {};
deba@1408
   453
deba@1408
   454
  template <typename Item>
deba@1408
   455
  class DefaultReader<std::set<Item> > 
deba@1408
   456
    : public InsertReader<std::set<Item> > {};
deba@1408
   457
deba@1852
   458
  template <typename Key, typename Value>
deba@1852
   459
  class DefaultReader<std::map<Key, Value> > 
deba@1852
   460
    : public InsertReader<std::map<Key, Value>,
deba@1852
   461
			  DefaultReader<std::pair<Key, Value> > > {};
deba@1852
   462
deba@1408
   463
  template <typename Item>
deba@1408
   464
  class DefaultReader<std::multiset<Item> > 
deba@1408
   465
    : public InsertReader<std::multiset<Item> > {};
deba@1408
   466
deba@1852
   467
  template <typename Key, typename Value>
deba@1852
   468
  class DefaultReader<std::multimap<Key, Value> > 
deba@1852
   469
    : public InsertReader<std::multimap<Key, Value>,
deba@1852
   470
			  DefaultReader<std::pair<Key, Value> > > {};
deba@1852
   471
deba@1852
   472
  template <typename First, typename Second>
deba@1852
   473
  class DefaultReader<std::pair<First, Second> > 
deba@1852
   474
    : public PairReader<std::pair<First, Second> > {};
deba@1852
   475
alpar@1946
   476
  /// \ingroup item_io
deba@1415
   477
  /// 
deba@1415
   478
  /// \brief The default item reader for skipping a value in the stream.
deba@1415
   479
  ///
deba@1415
   480
  /// The default item reader for skipping a value in the stream.
deba@1415
   481
  ///
deba@1415
   482
  /// \author Balazs Dezso
deba@1427
   483
  class DefaultSkipper : public DefaultReader<std::string> {};
deba@1415
   484
alpar@1946
   485
  /// \ingroup item_io  
deba@1408
   486
  /// \brief Standard ReaderTraits for the GraphReader class.
deba@1408
   487
  ///
deba@1408
   488
  /// Standard ReaderTraits for the GraphReader class.
deba@1408
   489
  /// It defines standard reading method for all type of value. 
deba@1408
   490
  /// \author Balazs Dezso
deba@1408
   491
  struct DefaultReaderTraits {
deba@1408
   492
deba@1408
   493
    template <typename _Value>
deba@1408
   494
    struct Reader : DefaultReader<_Value> {};
deba@1408
   495
deba@1408
   496
    typedef DefaultSkipper Skipper;
deba@1408
   497
deba@1408
   498
  };
deba@1408
   499
deba@1408
   500
}
deba@1408
   501
deba@1408
   502
#endif