gravatar
alpar (Alpar Juttner)
alpar@cs.elte.hu
Allow lgf file without Arc maps (#382) A single '-' character in the @arcs sectio header indicates that there is no arc map.
0 4 1
default
5 files changed with 204 insertions and 7 deletions:
↑ Collapse diff ↑
Ignore white space 6 line context
1
/* -*- mode: C++; indent-tabs-mode: nil; -*-
2
 *
3
 * This file is a part of LEMON, a generic C++ optimization library.
4
 *
5
 * Copyright (C) 2003-2011
6
 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
7
 * (Egervary Research Group on Combinatorial Optimization, EGRES).
8
 *
9
 * Permission to use, modify and distribute this software is granted
10
 * provided that this copyright notice appears in all copies. For
11
 * precise terms see the accompanying LICENSE file.
12
 *
13
 * This software is provided "AS IS" with no warranty of any kind,
14
 * express or implied, and with no claim as to its suitability for any
15
 * purpose.
16
 *
17
 */
18

	
19
#include <lemon/list_graph.h>
20
#include <lemon/lgf_reader.h>
21
#include "test_tools.h"
22

	
23
using namespace lemon;
24

	
25
char test_lgf[] =
26
  "@nodes\n"
27
  "label\n"
28
  "0\n"
29
  "1\n"
30
  "@arcs\n"
31
  "     label\n"
32
  "0 1  0\n"
33
  "1 0  1\n"
34
  "@attributes\n"
35
  "source 0\n"
36
  "target 1\n";
37

	
38
char test_lgf_nomap[] =
39
  "@nodes\n"
40
  "label\n"
41
  "0\n"
42
  "1\n"
43
  "@arcs\n"
44
  "     -\n"
45
  "0 1\n";
46

	
47
char test_lgf_bad1[] =
48
  "@nodes\n"
49
  "label\n"
50
  "0\n"
51
  "1\n"
52
  "@arcs\n"
53
  "     - another\n"
54
  "0 1\n";
55

	
56
char test_lgf_bad2[] =
57
  "@nodes\n"
58
  "label\n"
59
  "0\n"
60
  "1\n"
61
  "@arcs\n"
62
  "     label -\n"
63
  "0 1\n";
64

	
65

	
66
int main() 
67
{
68
  {
69
    ListDigraph d; 
70
    ListDigraph::Node s,t;
71
    ListDigraph::ArcMap<int> label(d);
72
    std::istringstream input(test_lgf);
73
    digraphReader(d, input).
74
      node("source", s).
75
      node("target", t).
76
      arcMap("label", label).
77
      run();
78
    check(countNodes(d) == 2,"There should be 2 nodes");
79
    check(countArcs(d) == 2,"There should be 2 arcs");
80
  }
81
  {
82
    ListGraph g;
83
    ListGraph::Node s,t;
84
    ListGraph::EdgeMap<int> label(g);
85
    std::istringstream input(test_lgf);
86
    graphReader(g, input).
87
      node("source", s).
88
      node("target", t).
89
      edgeMap("label", label).
90
      run();
91
    check(countNodes(g) == 2,"There should be 2 nodes");
92
    check(countEdges(g) == 2,"There should be 2 arcs");
93
  }
94

	
95
  {
96
    ListDigraph d; 
97
    std::istringstream input(test_lgf_nomap);
98
    digraphReader(d, input).
99
      run();
100
    check(countNodes(d) == 2,"There should be 2 nodes");
101
    check(countArcs(d) == 1,"There should be 1 arc");
102
  }
103
  {
104
    ListGraph g;
105
    std::istringstream input(test_lgf_nomap);
106
    graphReader(g, input).
107
      run();
108
    check(countNodes(g) == 2,"There should be 2 nodes");
109
    check(countEdges(g) == 1,"There should be 1 edge");
110
  }
111

	
112
  {
113
    ListDigraph d; 
114
    std::istringstream input(test_lgf_bad1);
115
    bool ok=false;
116
    try {
117
      digraphReader(d, input).
118
        run();
119
    }
120
    catch (FormatError& error) 
121
      {
122
        ok = true;
123
      }
124
    check(ok,"FormatError exception should have occured");
125
  }
126
  {
127
    ListGraph g;
128
    std::istringstream input(test_lgf_bad1);
129
    bool ok=false;
130
    try {
131
      graphReader(g, input).
132
        run();
133
    }
134
    catch (FormatError& error)
135
      {
136
        ok = true;
137
      }
138
    check(ok,"FormatError exception should have occured");
139
  }
140

	
141
  {
142
    ListDigraph d; 
143
    std::istringstream input(test_lgf_bad2);
144
    bool ok=false;
145
    try {
146
      digraphReader(d, input).
147
        run();
148
    }
149
    catch (FormatError& error)
150
      {
151
        ok = true;
152
      }
153
    check(ok,"FormatError exception should have occured");
154
  }
155
  {
156
    ListGraph g;
157
    std::istringstream input(test_lgf_bad2);
158
    bool ok=false;
159
    try {
160
      graphReader(g, input).
161
        run();
162
    }
163
    catch (FormatError& error)
164
      {
165
        ok = true;
166
      }
167
    check(ok,"FormatError exception should have occured");
168
  }
169
}
Ignore white space 6 line context
1 1
/* -*- mode: C++; indent-tabs-mode: nil; -*-
2 2
 *
3 3
 * This file is a part of LEMON, a generic C++ optimization library.
4 4
 *
5 5
 * Copyright (C) 2003-2008
6 6
 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
7 7
 * (Egervary Research Group on Combinatorial Optimization, EGRES).
8 8
 *
9 9
 * Permission to use, modify and distribute this software is granted
10 10
 * provided that this copyright notice appears in all copies. For
11 11
 * precise terms see the accompanying LICENSE file.
12 12
 *
13 13
 * This software is provided "AS IS" with no warranty of any kind,
14 14
 * express or implied, and with no claim as to its suitability for any
15 15
 * purpose.
16 16
 *
17 17
 */
18 18

	
19 19
namespace lemon {
20 20
/*!
21 21

	
22 22

	
23 23

	
24 24
\page lgf-format LEMON Graph Format (LGF)
25 25

	
26 26
The \e LGF is a <em>column oriented</em>
27 27
file format for storing graphs and associated data like
28 28
node and edge maps.
29 29

	
30 30
Each line with \c '#' first non-whitespace
31 31
character is considered as a comment line.
32 32

	
33 33
Otherwise the file consists of sections starting with
34 34
a header line. The header lines starts with an \c '@' character followed by the
35 35
type of section. The standard section types are \c \@nodes, \c
36 36
\@arcs and \c \@edges
37 37
and \@attributes. Each header line may also have an optional
38 38
\e name, which can be use to distinguish the sections of the same
39 39
type.
40 40

	
41 41
The standard sections are column oriented, each line consists of
42 42
<em>token</em>s separated by whitespaces. A token can be \e plain or
43 43
\e quoted. A plain token is just a sequence of non-whitespace characters,
44 44
while a quoted token is a
45 45
character sequence surrounded by double quotes, and it can also
46 46
contain whitespaces and escape sequences.
47 47

	
48 48
The \c \@nodes section describes a set of nodes and associated
49 49
maps. The first is a header line, its columns are the names of the
50 50
maps appearing in the following lines.
51 51
One of the maps must be called \c
52 52
"label", which plays special role in the file.
53 53
The following
54 54
non-empty lines until the next section describes nodes of the
55 55
graph. Each line contains the values of the node maps
56 56
associated to the current node.
57 57

	
58 58
\code
59 59
 @nodes
60 60
 label  coordinates  size    title
61 61
 1      (10,20)      10      "First node"
62 62
 2      (80,80)      8       "Second node"
63 63
 3      (40,10)      10      "Third node"
64 64
\endcode
65 65

	
66
The \c \@arcs section is very similar to the \c \@nodes section,
67
it again starts with a header line describing the names of the maps,
68
but the \c "label" map is not obligatory here. The following lines
69
describe the arcs. The first two tokens of each line are
70
the source and the target node of the arc, respectively, then come the map
66
The \c \@arcs section is very similar to the \c \@nodes section, it
67
again starts with a header line describing the names of the maps, but
68
the \c "label" map is not obligatory here. The following lines
69
describe the arcs. The first two tokens of each line are the source
70
and the target node of the arc, respectively, then come the map
71 71
values. The source and target tokens must be node labels.
72 72

	
73 73
\code
74 74
 @arcs
75 75
         capacity
76 76
 1   2   16
77 77
 1   3   12
78 78
 2   3   18
79 79
\endcode
80 80

	
81
If there is no map in the \c \@arcs section at all, then it must be
82
indicated by a sole '-' sign in the first line.
83

	
84
\code
85
 @arcs
86
         -
87
 1   2
88
 1   3
89
 2   3
90
\endcode
91

	
81 92
The \c \@edges is just a synonym of \c \@arcs. The \@arcs section can
82 93
also store the edge set of an undirected graph. In such case there is
83 94
a conventional method for store arc maps in the file, if two columns
84
has the same caption with \c '+' and \c '-' prefix, then these columns
95
have the same caption with \c '+' and \c '-' prefix, then these columns
85 96
can be regarded as the values of an arc map.
86 97

	
87 98
The \c \@attributes section contains key-value pairs, each line
88 99
consists of two tokens, an attribute name, and then an attribute
89 100
value. The value of the attribute could be also a label value of a
90 101
node or an edge, or even an edge label prefixed with \c '+' or \c '-',
91 102
which regards to the forward or backward directed arc of the
92 103
corresponding edge.
93 104

	
94 105
\code
95 106
 @attributes
96 107
 source 1
97 108
 target 3
98 109
 caption "LEMON test digraph"
99 110
\endcode
100 111

	
101 112
The \e LGF can contain extra sections, but there is no restriction on
102 113
the format of such sections.
103 114

	
104 115
*/
105 116
}
106 117

	
107 118
//  LocalWords:  whitespace whitespaces
Ignore white space 6 line context
1 1
/* -*- mode: C++; indent-tabs-mode: nil; -*-
2 2
 *
3 3
 * This file is a part of LEMON, a generic C++ optimization library.
4 4
 *
5
 * Copyright (C) 2003-2008
5
 * Copyright (C) 2003-2011
6 6
 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
7 7
 * (Egervary Research Group on Combinatorial Optimization, EGRES).
8 8
 *
9 9
 * Permission to use, modify and distribute this software is granted
10 10
 * provided that this copyright notice appears in all copies. For
11 11
 * precise terms see the accompanying LICENSE file.
12 12
 *
13 13
 * This software is provided "AS IS" with no warranty of any kind,
14 14
 * express or implied, and with no claim as to its suitability for any
15 15
 * purpose.
16 16
 *
17 17
 */
18 18

	
19 19
///\ingroup lemon_io
20 20
///\file
21 21
///\brief \ref lgf-format "LEMON Graph Format" reader.
22 22

	
23 23

	
24 24
#ifndef LEMON_LGF_READER_H
25 25
#define LEMON_LGF_READER_H
26 26

	
27 27
#include <iostream>
28 28
#include <fstream>
29 29
#include <sstream>
30 30

	
31 31
#include <set>
32 32
#include <map>
33 33

	
34 34
#include <lemon/core.h>
35 35

	
36 36
#include <lemon/lgf_writer.h>
37 37

	
38 38
#include <lemon/concept_check.h>
39 39
#include <lemon/concepts/maps.h>
40 40

	
41 41
namespace lemon {
42 42

	
43 43
  namespace _reader_bits {
44 44

	
45 45
    template <typename Value>
46 46
    struct DefaultConverter {
47 47
      Value operator()(const std::string& str) {
48 48
        std::istringstream is(str);
49 49
        Value value;
50 50
        if (!(is >> value)) {
51 51
          throw FormatError("Cannot read token");
52 52
        }
53 53

	
54 54
        char c;
55 55
        if (is >> std::ws >> c) {
56 56
          throw FormatError("Remaining characters in token");
57 57
        }
58 58
        return value;
59 59
      }
60 60
    };
61 61

	
62 62
    template <>
63 63
    struct DefaultConverter<std::string> {
64 64
      std::string operator()(const std::string& str) {
65 65
        return str;
66 66
      }
67 67
    };
68 68

	
69 69
    template <typename _Item>
70 70
    class MapStorageBase {
71 71
    public:
72 72
      typedef _Item Item;
73 73

	
74 74
    public:
75 75
      MapStorageBase() {}
76 76
      virtual ~MapStorageBase() {}
77 77

	
78 78
      virtual void set(const Item& item, const std::string& value) = 0;
79 79

	
80 80
    };
81 81

	
82 82
    template <typename _Item, typename _Map,
83 83
              typename _Converter = DefaultConverter<typename _Map::Value> >
84 84
    class MapStorage : public MapStorageBase<_Item> {
85 85
    public:
86 86
      typedef _Map Map;
87 87
      typedef _Converter Converter;
88 88
      typedef _Item Item;
89 89

	
90 90
    private:
91 91
      Map& _map;
92 92
      Converter _converter;
93 93

	
94 94
    public:
95 95
      MapStorage(Map& map, const Converter& converter = Converter())
96 96
        : _map(map), _converter(converter) {}
97 97
      virtual ~MapStorage() {}
98 98

	
99 99
      virtual void set(const Item& item ,const std::string& value) {
100 100
        _map.set(item, _converter(value));
101 101
      }
102 102
    };
103 103

	
104 104
    template <typename _Graph, bool _dir, typename _Map,
105 105
              typename _Converter = DefaultConverter<typename _Map::Value> >
106 106
    class GraphArcMapStorage : public MapStorageBase<typename _Graph::Edge> {
107 107
    public:
108 108
      typedef _Map Map;
109 109
      typedef _Converter Converter;
110 110
      typedef _Graph Graph;
111 111
      typedef typename Graph::Edge Item;
112 112
      static const bool dir = _dir;
113 113

	
114 114
    private:
115 115
      const Graph& _graph;
116 116
      Map& _map;
117 117
      Converter _converter;
118 118

	
119 119
    public:
120 120
      GraphArcMapStorage(const Graph& graph, Map& map,
121 121
                         const Converter& converter = Converter())
122 122
        : _graph(graph), _map(map), _converter(converter) {}
123 123
      virtual ~GraphArcMapStorage() {}
124 124

	
125 125
      virtual void set(const Item& item ,const std::string& value) {
126 126
        _map.set(_graph.direct(item, dir), _converter(value));
127 127
      }
128 128
    };
129 129

	
130 130
    class ValueStorageBase {
131 131
    public:
132 132
      ValueStorageBase() {}
133 133
      virtual ~ValueStorageBase() {}
134 134

	
135 135
      virtual void set(const std::string&) = 0;
136 136
    };
137 137

	
138 138
    template <typename _Value, typename _Converter = DefaultConverter<_Value> >
139 139
    class ValueStorage : public ValueStorageBase {
140 140
    public:
141 141
      typedef _Value Value;
142 142
      typedef _Converter Converter;
143 143

	
144 144
    private:
145 145
      Value& _value;
146 146
      Converter _converter;
147 147

	
148 148
    public:
149 149
      ValueStorage(Value& value, const Converter& converter = Converter())
150 150
        : _value(value), _converter(converter) {}
151 151

	
152 152
      virtual void set(const std::string& value) {
153 153
        _value = _converter(value);
154 154
      }
155 155
    };
156 156

	
157 157
    template <typename Value>
158 158
    struct MapLookUpConverter {
159 159
      const std::map<std::string, Value>& _map;
160 160

	
161 161
      MapLookUpConverter(const std::map<std::string, Value>& map)
162 162
        : _map(map) {}
163 163

	
164 164
      Value operator()(const std::string& str) {
165 165
        typename std::map<std::string, Value>::const_iterator it =
166 166
          _map.find(str);
167 167
        if (it == _map.end()) {
168 168
          std::ostringstream msg;
169 169
          msg << "Item not found: " << str;
170 170
          throw FormatError(msg.str());
171 171
        }
172 172
        return it->second;
173 173
      }
174 174
    };
175 175

	
176 176
    template <typename Graph>
177 177
    struct GraphArcLookUpConverter {
178 178
      const Graph& _graph;
179 179
      const std::map<std::string, typename Graph::Edge>& _map;
180 180

	
181 181
      GraphArcLookUpConverter(const Graph& graph,
182 182
                              const std::map<std::string,
183 183
                                             typename Graph::Edge>& map)
184 184
        : _graph(graph), _map(map) {}
185 185

	
186 186
      typename Graph::Arc operator()(const std::string& str) {
187 187
        if (str.empty() || (str[0] != '+' && str[0] != '-')) {
188 188
          throw FormatError("Item must start with '+' or '-'");
189 189
        }
190 190
        typename std::map<std::string, typename Graph::Edge>
191 191
          ::const_iterator it = _map.find(str.substr(1));
192 192
        if (it == _map.end()) {
193 193
          throw FormatError("Item not found");
194 194
        }
195 195
        return _graph.direct(it->second, str[0] == '+');
196 196
      }
197 197
    };
198 198

	
199 199
    inline bool isWhiteSpace(char c) {
200 200
      return c == ' ' || c == '\t' || c == '\v' ||
201 201
        c == '\n' || c == '\r' || c == '\f';
202 202
    }
203 203

	
204 204
    inline bool isOct(char c) {
205 205
      return '0' <= c && c <='7';
206 206
    }
207 207

	
208 208
    inline int valueOct(char c) {
209 209
      LEMON_ASSERT(isOct(c), "The character is not octal.");
210 210
      return c - '0';
211 211
    }
212 212

	
213 213
    inline bool isHex(char c) {
214 214
      return ('0' <= c && c <= '9') ||
215 215
        ('a' <= c && c <= 'z') ||
216 216
        ('A' <= c && c <= 'Z');
217 217
    }
218 218

	
219 219
    inline int valueHex(char c) {
220 220
      LEMON_ASSERT(isHex(c), "The character is not hexadecimal.");
221 221
      if ('0' <= c && c <= '9') return c - '0';
222 222
      if ('a' <= c && c <= 'z') return c - 'a' + 10;
223 223
      return c - 'A' + 10;
224 224
    }
225 225

	
226 226
    inline bool isIdentifierFirstChar(char c) {
227 227
      return ('a' <= c && c <= 'z') ||
228 228
        ('A' <= c && c <= 'Z') || c == '_';
229 229
    }
230 230

	
231 231
    inline bool isIdentifierChar(char c) {
232 232
      return isIdentifierFirstChar(c) ||
233 233
        ('0' <= c && c <= '9');
234 234
    }
235 235

	
236 236
    inline char readEscape(std::istream& is) {
237 237
      char c;
238 238
      if (!is.get(c))
239 239
        throw FormatError("Escape format error");
240 240

	
241 241
      switch (c) {
242 242
      case '\\':
243 243
        return '\\';
244 244
      case '\"':
245 245
        return '\"';
246 246
      case '\'':
247 247
        return '\'';
248 248
      case '\?':
249 249
        return '\?';
250 250
      case 'a':
251 251
        return '\a';
252 252
      case 'b':
253 253
        return '\b';
254 254
      case 'f':
255 255
        return '\f';
256 256
      case 'n':
257 257
        return '\n';
258 258
      case 'r':
259 259
        return '\r';
260 260
      case 't':
261 261
        return '\t';
262 262
      case 'v':
263 263
        return '\v';
264 264
      case 'x':
265 265
        {
266 266
          int code;
267 267
          if (!is.get(c) || !isHex(c))
268 268
            throw FormatError("Escape format error");
269 269
          else if (code = valueHex(c), !is.get(c) || !isHex(c)) is.putback(c);
270 270
          else code = code * 16 + valueHex(c);
271 271
          return code;
272 272
        }
273 273
      default:
274 274
        {
275 275
          int code;
276 276
          if (!isOct(c))
277 277
            throw FormatError("Escape format error");
278 278
          else if (code = valueOct(c), !is.get(c) || !isOct(c))
279 279
            is.putback(c);
280 280
          else if (code = code * 8 + valueOct(c), !is.get(c) || !isOct(c))
281 281
            is.putback(c);
282 282
          else code = code * 8 + valueOct(c);
283 283
          return code;
284 284
        }
285 285
      }
286 286
    }
287 287

	
288 288
    inline std::istream& readToken(std::istream& is, std::string& str) {
289 289
      std::ostringstream os;
290 290

	
291 291
      char c;
292 292
      is >> std::ws;
293 293

	
294 294
      if (!is.get(c))
295 295
        return is;
296 296

	
297 297
      if (c == '\"') {
298 298
        while (is.get(c) && c != '\"') {
299 299
          if (c == '\\')
300 300
            c = readEscape(is);
301 301
          os << c;
302 302
        }
303 303
        if (!is)
304 304
          throw FormatError("Quoted format error");
305 305
      } else {
306 306
        is.putback(c);
307 307
        while (is.get(c) && !isWhiteSpace(c)) {
308 308
          if (c == '\\')
309 309
            c = readEscape(is);
310 310
          os << c;
311 311
        }
312 312
        if (!is) {
313 313
          is.clear();
314 314
        } else {
315 315
          is.putback(c);
316 316
        }
317 317
      }
318 318
      str = os.str();
319 319
      return is;
320 320
    }
321 321

	
322 322
    class Section {
323 323
    public:
324 324
      virtual ~Section() {}
325 325
      virtual void process(std::istream& is, int& line_num) = 0;
326 326
    };
327 327

	
328 328
    template <typename Functor>
329 329
    class LineSection : public Section {
330 330
    private:
331 331

	
332 332
      Functor _functor;
333 333

	
334 334
    public:
335 335

	
336 336
      LineSection(const Functor& functor) : _functor(functor) {}
337 337
      virtual ~LineSection() {}
338 338

	
339 339
      virtual void process(std::istream& is, int& line_num) {
340 340
        char c;
341 341
        std::string line;
342 342
        while (is.get(c) && c != '@') {
343 343
          if (c == '\n') {
344 344
            ++line_num;
345 345
          } else if (c == '#') {
346 346
            getline(is, line);
347 347
            ++line_num;
348 348
          } else if (!isWhiteSpace(c)) {
349 349
            is.putback(c);
350 350
            getline(is, line);
351 351
            _functor(line);
352 352
            ++line_num;
353 353
          }
354 354
        }
355 355
        if (is) is.putback(c);
356 356
        else if (is.eof()) is.clear();
357 357
      }
358 358
    };
359 359

	
360 360
    template <typename Functor>
361 361
    class StreamSection : public Section {
362 362
    private:
363 363

	
364 364
      Functor _functor;
365 365

	
366 366
    public:
367 367

	
368 368
      StreamSection(const Functor& functor) : _functor(functor) {}
369 369
      virtual ~StreamSection() {}
370 370

	
371 371
      virtual void process(std::istream& is, int& line_num) {
372 372
        _functor(is, line_num);
373 373
        char c;
374 374
        std::string line;
375 375
        while (is.get(c) && c != '@') {
376 376
          if (c == '\n') {
377 377
            ++line_num;
378 378
          } else if (!isWhiteSpace(c)) {
379 379
            getline(is, line);
380 380
            ++line_num;
381 381
          }
382 382
        }
383 383
        if (is) is.putback(c);
384 384
        else if (is.eof()) is.clear();
385 385
      }
386 386
    };
387 387

	
388 388
  }
389 389

	
390 390
  template <typename Digraph>
391 391
  class DigraphReader;
392 392

	
393 393
  template <typename Digraph>
394 394
  DigraphReader<Digraph> digraphReader(Digraph& digraph, 
395 395
                                       std::istream& is = std::cin);
396 396
  template <typename Digraph>
397 397
  DigraphReader<Digraph> digraphReader(Digraph& digraph, const std::string& fn);
398 398
  template <typename Digraph>
399 399
  DigraphReader<Digraph> digraphReader(Digraph& digraph, const char *fn);
400 400

	
401 401
  /// \ingroup lemon_io
402 402
  ///
403 403
  /// \brief \ref lgf-format "LGF" reader for directed graphs
404 404
  ///
405 405
  /// This utility reads an \ref lgf-format "LGF" file.
406 406
  ///
407 407
  /// The reading method does a batch processing. The user creates a
408 408
  /// reader object, then various reading rules can be added to the
409 409
  /// reader, and eventually the reading is executed with the \c run()
410 410
  /// member function. A map reading rule can be added to the reader
411 411
  /// with the \c nodeMap() or \c arcMap() members. An optional
412 412
  /// converter parameter can also be added as a standard functor
413 413
  /// converting from \c std::string to the value type of the map. If it
414 414
  /// is set, it will determine how the tokens in the file should be
415 415
  /// converted to the value type of the map. If the functor is not set,
416 416
  /// then a default conversion will be used. One map can be read into
417 417
  /// multiple map objects at the same time. The \c attribute(), \c
418 418
  /// node() and \c arc() functions are used to add attribute reading
419 419
  /// rules.
420 420
  ///
421 421
  ///\code
422 422
  /// DigraphReader<Digraph>(digraph, std::cin).
423 423
  ///   nodeMap("coordinates", coord_map).
424 424
  ///   arcMap("capacity", cap_map).
425 425
  ///   node("source", src).
426 426
  ///   node("target", trg).
427 427
  ///   attribute("caption", caption).
428 428
  ///   run();
429 429
  ///\endcode
430 430
  ///
431 431
  /// By default the reader uses the first section in the file of the
432 432
  /// proper type. If a section has an optional name, then it can be
433 433
  /// selected for reading by giving an optional name parameter to the
434 434
  /// \c nodes(), \c arcs() or \c attributes() functions.
435 435
  ///
436 436
  /// The \c useNodes() and \c useArcs() functions are used to tell the reader
437 437
  /// that the nodes or arcs should not be constructed (added to the
438 438
  /// graph) during the reading, but instead the label map of the items
439 439
  /// are given as a parameter of these functions. An
440 440
  /// application of these functions is multipass reading, which is
441 441
  /// important if two \c \@arcs sections must be read from the
442 442
  /// file. In this case the first phase would read the node set and one
443 443
  /// of the arc sets, while the second phase would read the second arc
444 444
  /// set into an \e ArcSet class (\c SmartArcSet or \c ListArcSet).
445 445
  /// The previously read label node map should be passed to the \c
446 446
  /// useNodes() functions. Another application of multipass reading when
447 447
  /// paths are given as a node map or an arc map.
448 448
  /// It is impossible to read this in
449 449
  /// a single pass, because the arcs are not constructed when the node
450 450
  /// maps are read.
451 451
  template <typename _Digraph>
452 452
  class DigraphReader {
453 453
  public:
454 454

	
455 455
    typedef _Digraph Digraph;
456 456
    TEMPLATE_DIGRAPH_TYPEDEFS(Digraph);
457 457

	
458 458
  private:
459 459

	
460 460

	
461 461
    std::istream* _is;
462 462
    bool local_is;
463 463
    std::string _filename;
464 464

	
465 465
    Digraph& _digraph;
466 466

	
467 467
    std::string _nodes_caption;
468 468
    std::string _arcs_caption;
469 469
    std::string _attributes_caption;
470 470

	
471 471
    typedef std::map<std::string, Node> NodeIndex;
472 472
    NodeIndex _node_index;
473 473
    typedef std::map<std::string, Arc> ArcIndex;
474 474
    ArcIndex _arc_index;
475 475

	
476 476
    typedef std::vector<std::pair<std::string,
477 477
      _reader_bits::MapStorageBase<Node>*> > NodeMaps;
478 478
    NodeMaps _node_maps;
479 479

	
480 480
    typedef std::vector<std::pair<std::string,
481 481
      _reader_bits::MapStorageBase<Arc>*> >ArcMaps;
482 482
    ArcMaps _arc_maps;
483 483

	
484 484
    typedef std::multimap<std::string, _reader_bits::ValueStorageBase*>
485 485
      Attributes;
486 486
    Attributes _attributes;
487 487

	
488 488
    bool _use_nodes;
489 489
    bool _use_arcs;
490 490

	
491 491
    bool _skip_nodes;
492 492
    bool _skip_arcs;
493 493

	
494 494
    int line_num;
495 495
    std::istringstream line;
496 496

	
497 497
  public:
498 498

	
499 499
    /// \brief Constructor
500 500
    ///
501 501
    /// Construct a directed graph reader, which reads from the given
502 502
    /// input stream.
503 503
    DigraphReader(Digraph& digraph, std::istream& is = std::cin)
504 504
      : _is(&is), local_is(false), _digraph(digraph),
505 505
        _use_nodes(false), _use_arcs(false),
506 506
        _skip_nodes(false), _skip_arcs(false) {}
507 507

	
508 508
    /// \brief Constructor
509 509
    ///
510 510
    /// Construct a directed graph reader, which reads from the given
511 511
    /// file.
512 512
    DigraphReader(Digraph& digraph, const std::string& fn)
513 513
      : _is(new std::ifstream(fn.c_str())), local_is(true),
514 514
        _filename(fn), _digraph(digraph),
515 515
        _use_nodes(false), _use_arcs(false),
516 516
        _skip_nodes(false), _skip_arcs(false) {
517 517
      if (!(*_is)) {
518 518
        delete _is;
519 519
        throw IoError("Cannot open file", fn);
520 520
      }
521 521
    }
522 522

	
523 523
    /// \brief Constructor
524 524
    ///
525 525
    /// Construct a directed graph reader, which reads from the given
526 526
    /// file.
527 527
    DigraphReader(Digraph& digraph, const char* fn)
528 528
      : _is(new std::ifstream(fn)), local_is(true),
529 529
        _filename(fn), _digraph(digraph),
530 530
        _use_nodes(false), _use_arcs(false),
531 531
        _skip_nodes(false), _skip_arcs(false) {
532 532
      if (!(*_is)) {
533 533
        delete _is;
534 534
        throw IoError("Cannot open file", fn);
535 535
      }
536 536
    }
537 537

	
538 538
    /// \brief Destructor
539 539
    ~DigraphReader() {
540 540
      for (typename NodeMaps::iterator it = _node_maps.begin();
541 541
           it != _node_maps.end(); ++it) {
542 542
        delete it->second;
543 543
      }
544 544

	
545 545
      for (typename ArcMaps::iterator it = _arc_maps.begin();
546 546
           it != _arc_maps.end(); ++it) {
547 547
        delete it->second;
548 548
      }
549 549

	
550 550
      for (typename Attributes::iterator it = _attributes.begin();
551 551
           it != _attributes.end(); ++it) {
552 552
        delete it->second;
553 553
      }
554 554

	
555 555
      if (local_is) {
556 556
        delete _is;
557 557
      }
558 558

	
559 559
    }
560 560

	
561 561
  private:
562 562

	
563 563
    template <typename DGR>
564 564
    friend DigraphReader<DGR> digraphReader(DGR& digraph, std::istream& is);
565 565
    template <typename DGR>
566 566
    friend DigraphReader<DGR> digraphReader(DGR& digraph, 
567 567
                                            const std::string& fn);
568 568
    template <typename DGR>
569 569
    friend DigraphReader<DGR> digraphReader(DGR& digraph, const char *fn);
570 570

	
571 571
    DigraphReader(DigraphReader& other)
572 572
      : _is(other._is), local_is(other.local_is), _digraph(other._digraph),
573 573
        _use_nodes(other._use_nodes), _use_arcs(other._use_arcs),
574 574
        _skip_nodes(other._skip_nodes), _skip_arcs(other._skip_arcs) {
575 575

	
576 576
      other._is = 0;
577 577
      other.local_is = false;
578 578

	
579 579
      _node_index.swap(other._node_index);
580 580
      _arc_index.swap(other._arc_index);
581 581

	
582 582
      _node_maps.swap(other._node_maps);
583 583
      _arc_maps.swap(other._arc_maps);
584 584
      _attributes.swap(other._attributes);
585 585

	
586 586
      _nodes_caption = other._nodes_caption;
587 587
      _arcs_caption = other._arcs_caption;
588 588
      _attributes_caption = other._attributes_caption;
589 589

	
590 590
    }
591 591

	
592 592
    DigraphReader& operator=(const DigraphReader&);
593 593

	
594 594
  public:
595 595

	
596 596
    /// \name Reading rules
597 597
    /// @{
598 598

	
599 599
    /// \brief Node map reading rule
600 600
    ///
601 601
    /// Add a node map reading rule to the reader.
602 602
    template <typename Map>
603 603
    DigraphReader& nodeMap(const std::string& caption, Map& map) {
604 604
      checkConcept<concepts::WriteMap<Node, typename Map::Value>, Map>();
605 605
      _reader_bits::MapStorageBase<Node>* storage =
606 606
        new _reader_bits::MapStorage<Node, Map>(map);
607 607
      _node_maps.push_back(std::make_pair(caption, storage));
608 608
      return *this;
609 609
    }
610 610

	
611 611
    /// \brief Node map reading rule
612 612
    ///
613 613
    /// Add a node map reading rule with specialized converter to the
614 614
    /// reader.
615 615
    template <typename Map, typename Converter>
616 616
    DigraphReader& nodeMap(const std::string& caption, Map& map,
617 617
                           const Converter& converter = Converter()) {
618 618
      checkConcept<concepts::WriteMap<Node, typename Map::Value>, Map>();
619 619
      _reader_bits::MapStorageBase<Node>* storage =
620 620
        new _reader_bits::MapStorage<Node, Map, Converter>(map, converter);
621 621
      _node_maps.push_back(std::make_pair(caption, storage));
622 622
      return *this;
623 623
    }
624 624

	
625 625
    /// \brief Arc map reading rule
626 626
    ///
627 627
    /// Add an arc map reading rule to the reader.
628 628
    template <typename Map>
629 629
    DigraphReader& arcMap(const std::string& caption, Map& map) {
630 630
      checkConcept<concepts::WriteMap<Arc, typename Map::Value>, Map>();
631 631
      _reader_bits::MapStorageBase<Arc>* storage =
632 632
        new _reader_bits::MapStorage<Arc, Map>(map);
633 633
      _arc_maps.push_back(std::make_pair(caption, storage));
634 634
      return *this;
635 635
    }
636 636

	
637 637
    /// \brief Arc map reading rule
638 638
    ///
639 639
    /// Add an arc map reading rule with specialized converter to the
640 640
    /// reader.
641 641
    template <typename Map, typename Converter>
642 642
    DigraphReader& arcMap(const std::string& caption, Map& map,
643 643
                          const Converter& converter = Converter()) {
644 644
      checkConcept<concepts::WriteMap<Arc, typename Map::Value>, Map>();
645 645
      _reader_bits::MapStorageBase<Arc>* storage =
646 646
        new _reader_bits::MapStorage<Arc, Map, Converter>(map, converter);
647 647
      _arc_maps.push_back(std::make_pair(caption, storage));
648 648
      return *this;
649 649
    }
650 650

	
651 651
    /// \brief Attribute reading rule
652 652
    ///
653 653
    /// Add an attribute reading rule to the reader.
654 654
    template <typename Value>
655 655
    DigraphReader& attribute(const std::string& caption, Value& value) {
656 656
      _reader_bits::ValueStorageBase* storage =
657 657
        new _reader_bits::ValueStorage<Value>(value);
658 658
      _attributes.insert(std::make_pair(caption, storage));
659 659
      return *this;
660 660
    }
661 661

	
662 662
    /// \brief Attribute reading rule
663 663
    ///
664 664
    /// Add an attribute reading rule with specialized converter to the
665 665
    /// reader.
666 666
    template <typename Value, typename Converter>
667 667
    DigraphReader& attribute(const std::string& caption, Value& value,
668 668
                             const Converter& converter = Converter()) {
669 669
      _reader_bits::ValueStorageBase* storage =
670 670
        new _reader_bits::ValueStorage<Value, Converter>(value, converter);
671 671
      _attributes.insert(std::make_pair(caption, storage));
672 672
      return *this;
673 673
    }
674 674

	
675 675
    /// \brief Node reading rule
676 676
    ///
677 677
    /// Add a node reading rule to reader.
678 678
    DigraphReader& node(const std::string& caption, Node& node) {
679 679
      typedef _reader_bits::MapLookUpConverter<Node> Converter;
680 680
      Converter converter(_node_index);
681 681
      _reader_bits::ValueStorageBase* storage =
682 682
        new _reader_bits::ValueStorage<Node, Converter>(node, converter);
683 683
      _attributes.insert(std::make_pair(caption, storage));
684 684
      return *this;
685 685
    }
686 686

	
687 687
    /// \brief Arc reading rule
688 688
    ///
689 689
    /// Add an arc reading rule to reader.
690 690
    DigraphReader& arc(const std::string& caption, Arc& arc) {
691 691
      typedef _reader_bits::MapLookUpConverter<Arc> Converter;
692 692
      Converter converter(_arc_index);
693 693
      _reader_bits::ValueStorageBase* storage =
694 694
        new _reader_bits::ValueStorage<Arc, Converter>(arc, converter);
695 695
      _attributes.insert(std::make_pair(caption, storage));
696 696
      return *this;
697 697
    }
698 698

	
699 699
    /// @}
700 700

	
701 701
    /// \name Select section by name
702 702
    /// @{
703 703

	
704 704
    /// \brief Set \c \@nodes section to be read
705 705
    ///
706 706
    /// Set \c \@nodes section to be read
707 707
    DigraphReader& nodes(const std::string& caption) {
708 708
      _nodes_caption = caption;
709 709
      return *this;
710 710
    }
711 711

	
712 712
    /// \brief Set \c \@arcs section to be read
713 713
    ///
714 714
    /// Set \c \@arcs section to be read
715 715
    DigraphReader& arcs(const std::string& caption) {
716 716
      _arcs_caption = caption;
717 717
      return *this;
718 718
    }
719 719

	
720 720
    /// \brief Set \c \@attributes section to be read
721 721
    ///
722 722
    /// Set \c \@attributes section to be read
723 723
    DigraphReader& attributes(const std::string& caption) {
724 724
      _attributes_caption = caption;
725 725
      return *this;
726 726
    }
727 727

	
728 728
    /// @}
729 729

	
730 730
    /// \name Using previously constructed node or arc set
731 731
    /// @{
732 732

	
733 733
    /// \brief Use previously constructed node set
734 734
    ///
735 735
    /// Use previously constructed node set, and specify the node
736 736
    /// label map.
737 737
    template <typename Map>
738 738
    DigraphReader& useNodes(const Map& map) {
739 739
      checkConcept<concepts::ReadMap<Node, typename Map::Value>, Map>();
740 740
      LEMON_ASSERT(!_use_nodes, "Multiple usage of useNodes() member");
741 741
      _use_nodes = true;
742 742
      _writer_bits::DefaultConverter<typename Map::Value> converter;
743 743
      for (NodeIt n(_digraph); n != INVALID; ++n) {
744 744
        _node_index.insert(std::make_pair(converter(map[n]), n));
745 745
      }
746 746
      return *this;
747 747
    }
748 748

	
749 749
    /// \brief Use previously constructed node set
750 750
    ///
751 751
    /// Use previously constructed node set, and specify the node
752 752
    /// label map and a functor which converts the label map values to
753 753
    /// \c std::string.
754 754
    template <typename Map, typename Converter>
755 755
    DigraphReader& useNodes(const Map& map,
756 756
                            const Converter& converter = Converter()) {
757 757
      checkConcept<concepts::ReadMap<Node, typename Map::Value>, Map>();
758 758
      LEMON_ASSERT(!_use_nodes, "Multiple usage of useNodes() member");
759 759
      _use_nodes = true;
760 760
      for (NodeIt n(_digraph); n != INVALID; ++n) {
761 761
        _node_index.insert(std::make_pair(converter(map[n]), n));
762 762
      }
763 763
      return *this;
764 764
    }
765 765

	
766 766
    /// \brief Use previously constructed arc set
767 767
    ///
768 768
    /// Use previously constructed arc set, and specify the arc
769 769
    /// label map.
770 770
    template <typename Map>
771 771
    DigraphReader& useArcs(const Map& map) {
772 772
      checkConcept<concepts::ReadMap<Arc, typename Map::Value>, Map>();
773 773
      LEMON_ASSERT(!_use_arcs, "Multiple usage of useArcs() member");
774 774
      _use_arcs = true;
775 775
      _writer_bits::DefaultConverter<typename Map::Value> converter;
776 776
      for (ArcIt a(_digraph); a != INVALID; ++a) {
777 777
        _arc_index.insert(std::make_pair(converter(map[a]), a));
778 778
      }
779 779
      return *this;
780 780
    }
781 781

	
782 782
    /// \brief Use previously constructed arc set
783 783
    ///
784 784
    /// Use previously constructed arc set, and specify the arc
785 785
    /// label map and a functor which converts the label map values to
786 786
    /// \c std::string.
787 787
    template <typename Map, typename Converter>
788 788
    DigraphReader& useArcs(const Map& map,
789 789
                           const Converter& converter = Converter()) {
790 790
      checkConcept<concepts::ReadMap<Arc, typename Map::Value>, Map>();
791 791
      LEMON_ASSERT(!_use_arcs, "Multiple usage of useArcs() member");
792 792
      _use_arcs = true;
793 793
      for (ArcIt a(_digraph); a != INVALID; ++a) {
794 794
        _arc_index.insert(std::make_pair(converter(map[a]), a));
795 795
      }
796 796
      return *this;
797 797
    }
798 798

	
799 799
    /// \brief Skips the reading of node section
800 800
    ///
801 801
    /// Omit the reading of the node section. This implies that each node
802 802
    /// map reading rule will be abandoned, and the nodes of the graph
803 803
    /// will not be constructed, which usually cause that the arc set
804 804
    /// could not be read due to lack of node name resolving.
805 805
    /// Therefore \c skipArcs() function should also be used, or
806 806
    /// \c useNodes() should be used to specify the label of the nodes.
807 807
    DigraphReader& skipNodes() {
808 808
      LEMON_ASSERT(!_skip_nodes, "Skip nodes already set");
809 809
      _skip_nodes = true;
810 810
      return *this;
811 811
    }
812 812

	
813 813
    /// \brief Skips the reading of arc section
814 814
    ///
815 815
    /// Omit the reading of the arc section. This implies that each arc
816 816
    /// map reading rule will be abandoned, and the arcs of the graph
817 817
    /// will not be constructed.
818 818
    DigraphReader& skipArcs() {
819 819
      LEMON_ASSERT(!_skip_arcs, "Skip arcs already set");
820 820
      _skip_arcs = true;
821 821
      return *this;
822 822
    }
823 823

	
824 824
    /// @}
825 825

	
826 826
  private:
827 827

	
828 828
    bool readLine() {
829 829
      std::string str;
830 830
      while(++line_num, std::getline(*_is, str)) {
831 831
        line.clear(); line.str(str);
832 832
        char c;
833 833
        if (line >> std::ws >> c && c != '#') {
834 834
          line.putback(c);
835 835
          return true;
836 836
        }
837 837
      }
838 838
      return false;
839 839
    }
840 840

	
841 841
    bool readSuccess() {
842 842
      return static_cast<bool>(*_is);
843 843
    }
844 844

	
845 845
    void skipSection() {
846 846
      char c;
847 847
      while (readSuccess() && line >> c && c != '@') {
848 848
        readLine();
849 849
      }
850 850
      line.putback(c);
851 851
    }
852 852

	
853 853
    void readNodes() {
854 854

	
855 855
      std::vector<int> map_index(_node_maps.size());
856 856
      int map_num, label_index;
857 857

	
858 858
      char c;
859 859
      if (!readLine() || !(line >> c) || c == '@') {
860 860
        if (readSuccess() && line) line.putback(c);
861 861
        if (!_node_maps.empty())
862 862
          throw FormatError("Cannot find map names");
863 863
        return;
864 864
      }
865 865
      line.putback(c);
866 866

	
867 867
      {
868 868
        std::map<std::string, int> maps;
869 869

	
870 870
        std::string map;
871 871
        int index = 0;
872 872
        while (_reader_bits::readToken(line, map)) {
873 873
          if (maps.find(map) != maps.end()) {
874 874
            std::ostringstream msg;
875 875
            msg << "Multiple occurence of node map: " << map;
876 876
            throw FormatError(msg.str());
877 877
          }
878 878
          maps.insert(std::make_pair(map, index));
879 879
          ++index;
880 880
        }
881 881

	
882 882
        for (int i = 0; i < static_cast<int>(_node_maps.size()); ++i) {
883 883
          std::map<std::string, int>::iterator jt =
884 884
            maps.find(_node_maps[i].first);
885 885
          if (jt == maps.end()) {
886 886
            std::ostringstream msg;
887 887
            msg << "Map not found: " << _node_maps[i].first;
888 888
            throw FormatError(msg.str());
889 889
          }
890 890
          map_index[i] = jt->second;
891 891
        }
892 892

	
893 893
        {
894 894
          std::map<std::string, int>::iterator jt = maps.find("label");
895 895
          if (jt != maps.end()) {
896 896
            label_index = jt->second;
897 897
          } else {
898 898
            label_index = -1;
899 899
          }
900 900
        }
901 901
        map_num = maps.size();
902 902
      }
903 903

	
904 904
      while (readLine() && line >> c && c != '@') {
905 905
        line.putback(c);
906 906

	
907 907
        std::vector<std::string> tokens(map_num);
908 908
        for (int i = 0; i < map_num; ++i) {
909 909
          if (!_reader_bits::readToken(line, tokens[i])) {
910 910
            std::ostringstream msg;
911 911
            msg << "Column not found (" << i + 1 << ")";
912 912
            throw FormatError(msg.str());
913 913
          }
914 914
        }
915 915
        if (line >> std::ws >> c)
916 916
          throw FormatError("Extra character at the end of line");
917 917

	
918 918
        Node n;
919 919
        if (!_use_nodes) {
920 920
          n = _digraph.addNode();
921 921
          if (label_index != -1)
922 922
            _node_index.insert(std::make_pair(tokens[label_index], n));
923 923
        } else {
924 924
          if (label_index == -1)
925 925
            throw FormatError("Label map not found");
926 926
          typename std::map<std::string, Node>::iterator it =
927 927
            _node_index.find(tokens[label_index]);
928 928
          if (it == _node_index.end()) {
929 929
            std::ostringstream msg;
930 930
            msg << "Node with label not found: " << tokens[label_index];
931 931
            throw FormatError(msg.str());
932 932
          }
933 933
          n = it->second;
934 934
        }
935 935

	
936 936
        for (int i = 0; i < static_cast<int>(_node_maps.size()); ++i) {
937 937
          _node_maps[i].second->set(n, tokens[map_index[i]]);
938 938
        }
939 939

	
940 940
      }
941 941
      if (readSuccess()) {
942 942
        line.putback(c);
943 943
      }
944 944
    }
945 945

	
946 946
    void readArcs() {
947 947

	
948 948
      std::vector<int> map_index(_arc_maps.size());
949 949
      int map_num, label_index;
950 950

	
951 951
      char c;
952 952
      if (!readLine() || !(line >> c) || c == '@') {
953 953
        if (readSuccess() && line) line.putback(c);
954 954
        if (!_arc_maps.empty())
955 955
          throw FormatError("Cannot find map names");
956 956
        return;
957 957
      }
958 958
      line.putback(c);
959 959

	
960 960
      {
961 961
        std::map<std::string, int> maps;
962 962

	
963 963
        std::string map;
964 964
        int index = 0;
965 965
        while (_reader_bits::readToken(line, map)) {
966
          if(map == "-") {
967
              if(index!=0)
968
                throw FormatError("'-' is not allowed as a map name");
969
              else if (line >> std::ws >> c)
970
                throw FormatError("Extra character at the end of line");
971
              else break;
972
            }
966 973
          if (maps.find(map) != maps.end()) {
967 974
            std::ostringstream msg;
968 975
            msg << "Multiple occurence of arc map: " << map;
969 976
            throw FormatError(msg.str());
970 977
          }
971 978
          maps.insert(std::make_pair(map, index));
972 979
          ++index;
973 980
        }
974 981

	
975 982
        for (int i = 0; i < static_cast<int>(_arc_maps.size()); ++i) {
976 983
          std::map<std::string, int>::iterator jt =
977 984
            maps.find(_arc_maps[i].first);
978 985
          if (jt == maps.end()) {
979 986
            std::ostringstream msg;
980 987
            msg << "Map not found: " << _arc_maps[i].first;
981 988
            throw FormatError(msg.str());
982 989
          }
983 990
          map_index[i] = jt->second;
984 991
        }
985 992

	
986 993
        {
987 994
          std::map<std::string, int>::iterator jt = maps.find("label");
988 995
          if (jt != maps.end()) {
989 996
            label_index = jt->second;
990 997
          } else {
991 998
            label_index = -1;
992 999
          }
993 1000
        }
994 1001
        map_num = maps.size();
995 1002
      }
996 1003

	
997 1004
      while (readLine() && line >> c && c != '@') {
998 1005
        line.putback(c);
999 1006

	
1000 1007
        std::string source_token;
1001 1008
        std::string target_token;
1002 1009

	
1003 1010
        if (!_reader_bits::readToken(line, source_token))
1004 1011
          throw FormatError("Source not found");
1005 1012

	
1006 1013
        if (!_reader_bits::readToken(line, target_token))
1007 1014
          throw FormatError("Target not found");
1008 1015

	
1009 1016
        std::vector<std::string> tokens(map_num);
1010 1017
        for (int i = 0; i < map_num; ++i) {
1011 1018
          if (!_reader_bits::readToken(line, tokens[i])) {
1012 1019
            std::ostringstream msg;
1013 1020
            msg << "Column not found (" << i + 1 << ")";
1014 1021
            throw FormatError(msg.str());
1015 1022
          }
1016 1023
        }
1017 1024
        if (line >> std::ws >> c)
1018 1025
          throw FormatError("Extra character at the end of line");
1019 1026

	
1020 1027
        Arc a;
1021 1028
        if (!_use_arcs) {
1022 1029

	
1023 1030
          typename NodeIndex::iterator it;
1024 1031

	
1025 1032
          it = _node_index.find(source_token);
1026 1033
          if (it == _node_index.end()) {
1027 1034
            std::ostringstream msg;
1028 1035
            msg << "Item not found: " << source_token;
1029 1036
            throw FormatError(msg.str());
1030 1037
          }
1031 1038
          Node source = it->second;
1032 1039

	
1033 1040
          it = _node_index.find(target_token);
1034 1041
          if (it == _node_index.end()) {
1035 1042
            std::ostringstream msg;
1036 1043
            msg << "Item not found: " << target_token;
1037 1044
            throw FormatError(msg.str());
1038 1045
          }
1039 1046
          Node target = it->second;
1040 1047

	
1041 1048
          a = _digraph.addArc(source, target);
1042 1049
          if (label_index != -1)
1043 1050
            _arc_index.insert(std::make_pair(tokens[label_index], a));
1044 1051
        } else {
1045 1052
          if (label_index == -1)
1046 1053
            throw FormatError("Label map not found");
1047 1054
          typename std::map<std::string, Arc>::iterator it =
1048 1055
            _arc_index.find(tokens[label_index]);
1049 1056
          if (it == _arc_index.end()) {
1050 1057
            std::ostringstream msg;
1051 1058
            msg << "Arc with label not found: " << tokens[label_index];
1052 1059
            throw FormatError(msg.str());
1053 1060
          }
1054 1061
          a = it->second;
1055 1062
        }
1056 1063

	
1057 1064
        for (int i = 0; i < static_cast<int>(_arc_maps.size()); ++i) {
1058 1065
          _arc_maps[i].second->set(a, tokens[map_index[i]]);
1059 1066
        }
1060 1067

	
1061 1068
      }
1062 1069
      if (readSuccess()) {
1063 1070
        line.putback(c);
1064 1071
      }
1065 1072
    }
1066 1073

	
1067 1074
    void readAttributes() {
1068 1075

	
1069 1076
      std::set<std::string> read_attr;
1070 1077

	
1071 1078
      char c;
1072 1079
      while (readLine() && line >> c && c != '@') {
1073 1080
        line.putback(c);
1074 1081

	
1075 1082
        std::string attr, token;
1076 1083
        if (!_reader_bits::readToken(line, attr))
1077 1084
          throw FormatError("Attribute name not found");
1078 1085
        if (!_reader_bits::readToken(line, token))
1079 1086
          throw FormatError("Attribute value not found");
1080 1087
        if (line >> c)
1081 1088
          throw FormatError("Extra character at the end of line");
1082 1089

	
1083 1090
        {
1084 1091
          std::set<std::string>::iterator it = read_attr.find(attr);
1085 1092
          if (it != read_attr.end()) {
1086 1093
            std::ostringstream msg;
1087 1094
            msg << "Multiple occurence of attribute: " << attr;
1088 1095
            throw FormatError(msg.str());
1089 1096
          }
1090 1097
          read_attr.insert(attr);
1091 1098
        }
1092 1099

	
1093 1100
        {
1094 1101
          typename Attributes::iterator it = _attributes.lower_bound(attr);
1095 1102
          while (it != _attributes.end() && it->first == attr) {
1096 1103
            it->second->set(token);
1097 1104
            ++it;
1098 1105
          }
1099 1106
        }
1100 1107

	
1101 1108
      }
1102 1109
      if (readSuccess()) {
1103 1110
        line.putback(c);
1104 1111
      }
1105 1112
      for (typename Attributes::iterator it = _attributes.begin();
1106 1113
           it != _attributes.end(); ++it) {
1107 1114
        if (read_attr.find(it->first) == read_attr.end()) {
1108 1115
          std::ostringstream msg;
1109 1116
          msg << "Attribute not found: " << it->first;
1110 1117
          throw FormatError(msg.str());
1111 1118
        }
1112 1119
      }
1113 1120
    }
1114 1121

	
1115 1122
  public:
1116 1123

	
1117 1124
    /// \name Execution of the reader
1118 1125
    /// @{
1119 1126

	
1120 1127
    /// \brief Start the batch processing
1121 1128
    ///
1122 1129
    /// This function starts the batch processing
1123 1130
    void run() {
1124 1131
      LEMON_ASSERT(_is != 0, "This reader assigned to an other reader");
1125 1132

	
1126 1133
      bool nodes_done = _skip_nodes;
1127 1134
      bool arcs_done = _skip_arcs;
1128 1135
      bool attributes_done = false;
1129 1136

	
1130 1137
      line_num = 0;
1131 1138
      readLine();
1132 1139
      skipSection();
1133 1140

	
1134 1141
      while (readSuccess()) {
1135 1142
        try {
1136 1143
          char c;
1137 1144
          std::string section, caption;
1138 1145
          line >> c;
1139 1146
          _reader_bits::readToken(line, section);
1140 1147
          _reader_bits::readToken(line, caption);
1141 1148

	
1142 1149
          if (line >> c)
1143 1150
            throw FormatError("Extra character at the end of line");
1144 1151

	
1145 1152
          if (section == "nodes" && !nodes_done) {
1146 1153
            if (_nodes_caption.empty() || _nodes_caption == caption) {
1147 1154
              readNodes();
1148 1155
              nodes_done = true;
1149 1156
            }
1150 1157
          } else if ((section == "arcs" || section == "edges") &&
1151 1158
                     !arcs_done) {
1152 1159
            if (_arcs_caption.empty() || _arcs_caption == caption) {
1153 1160
              readArcs();
1154 1161
              arcs_done = true;
1155 1162
            }
1156 1163
          } else if (section == "attributes" && !attributes_done) {
1157 1164
            if (_attributes_caption.empty() || _attributes_caption == caption) {
1158 1165
              readAttributes();
1159 1166
              attributes_done = true;
1160 1167
            }
1161 1168
          } else {
1162 1169
            readLine();
1163 1170
            skipSection();
1164 1171
          }
1165 1172
        } catch (FormatError& error) {
1166 1173
          error.line(line_num);
1167 1174
          error.file(_filename);
1168 1175
          throw;
1169 1176
        }
1170 1177
      }
1171 1178

	
1172 1179
      if (!nodes_done) {
1173 1180
        throw FormatError("Section @nodes not found");
1174 1181
      }
1175 1182

	
1176 1183
      if (!arcs_done) {
1177 1184
        throw FormatError("Section @arcs not found");
1178 1185
      }
1179 1186

	
1180 1187
      if (!attributes_done && !_attributes.empty()) {
1181 1188
        throw FormatError("Section @attributes not found");
1182 1189
      }
1183 1190

	
1184 1191
    }
1185 1192

	
1186 1193
    /// @}
1187 1194

	
1188 1195
  };
1189 1196

	
1190 1197
  /// \brief Return a \ref DigraphReader class
1191 1198
  ///
1192 1199
  /// This function just returns a \ref DigraphReader class.
1193 1200
  /// \relates DigraphReader
1194 1201
  template <typename Digraph>
1195 1202
  DigraphReader<Digraph> digraphReader(Digraph& digraph, std::istream& is) {
1196 1203
    DigraphReader<Digraph> tmp(digraph, is);
1197 1204
    return tmp;
1198 1205
  }
1199 1206

	
1200 1207
  /// \brief Return a \ref DigraphReader class
1201 1208
  ///
1202 1209
  /// This function just returns a \ref DigraphReader class.
1203 1210
  /// \relates DigraphReader
1204 1211
  template <typename Digraph>
1205 1212
  DigraphReader<Digraph> digraphReader(Digraph& digraph,
1206 1213
                                       const std::string& fn) {
1207 1214
    DigraphReader<Digraph> tmp(digraph, fn);
1208 1215
    return tmp;
1209 1216
  }
1210 1217

	
1211 1218
  /// \brief Return a \ref DigraphReader class
1212 1219
  ///
1213 1220
  /// This function just returns a \ref DigraphReader class.
1214 1221
  /// \relates DigraphReader
1215 1222
  template <typename Digraph>
1216 1223
  DigraphReader<Digraph> digraphReader(Digraph& digraph, const char* fn) {
1217 1224
    DigraphReader<Digraph> tmp(digraph, fn);
1218 1225
    return tmp;
1219 1226
  }
1220 1227

	
1221 1228
  template <typename Graph>
1222 1229
  class GraphReader;
1223 1230
 
1224 1231
  template <typename Graph>
1225 1232
  GraphReader<Graph> graphReader(Graph& graph, 
1226 1233
                                 std::istream& is = std::cin);
1227 1234
  template <typename Graph>
1228 1235
  GraphReader<Graph> graphReader(Graph& graph, const std::string& fn);
1229 1236
  template <typename Graph>
1230 1237
  GraphReader<Graph> graphReader(Graph& graph, const char *fn);
1231 1238

	
1232 1239
  /// \ingroup lemon_io
1233 1240
  ///
1234 1241
  /// \brief \ref lgf-format "LGF" reader for undirected graphs
1235 1242
  ///
1236 1243
  /// This utility reads an \ref lgf-format "LGF" file.
1237 1244
  ///
1238 1245
  /// It can be used almost the same way as \c DigraphReader.
1239 1246
  /// The only difference is that this class can handle edges and
1240 1247
  /// edge maps as well as arcs and arc maps.
1241 1248
  ///
1242 1249
  /// The columns in the \c \@edges (or \c \@arcs) section are the
1243 1250
  /// edge maps. However, if there are two maps with the same name
1244 1251
  /// prefixed with \c '+' and \c '-', then these can be read into an
1245 1252
  /// arc map.  Similarly, an attribute can be read into an arc, if
1246 1253
  /// it's value is an edge label prefixed with \c '+' or \c '-'.
1247 1254
  template <typename _Graph>
1248 1255
  class GraphReader {
1249 1256
  public:
1250 1257

	
1251 1258
    typedef _Graph Graph;
1252 1259
    TEMPLATE_GRAPH_TYPEDEFS(Graph);
1253 1260

	
1254 1261
  private:
1255 1262

	
1256 1263
    std::istream* _is;
1257 1264
    bool local_is;
1258 1265
    std::string _filename;
1259 1266

	
1260 1267
    Graph& _graph;
1261 1268

	
1262 1269
    std::string _nodes_caption;
1263 1270
    std::string _edges_caption;
1264 1271
    std::string _attributes_caption;
1265 1272

	
1266 1273
    typedef std::map<std::string, Node> NodeIndex;
1267 1274
    NodeIndex _node_index;
1268 1275
    typedef std::map<std::string, Edge> EdgeIndex;
1269 1276
    EdgeIndex _edge_index;
1270 1277

	
1271 1278
    typedef std::vector<std::pair<std::string,
1272 1279
      _reader_bits::MapStorageBase<Node>*> > NodeMaps;
1273 1280
    NodeMaps _node_maps;
1274 1281

	
1275 1282
    typedef std::vector<std::pair<std::string,
1276 1283
      _reader_bits::MapStorageBase<Edge>*> > EdgeMaps;
1277 1284
    EdgeMaps _edge_maps;
1278 1285

	
1279 1286
    typedef std::multimap<std::string, _reader_bits::ValueStorageBase*>
1280 1287
      Attributes;
1281 1288
    Attributes _attributes;
1282 1289

	
1283 1290
    bool _use_nodes;
1284 1291
    bool _use_edges;
1285 1292

	
1286 1293
    bool _skip_nodes;
1287 1294
    bool _skip_edges;
1288 1295

	
1289 1296
    int line_num;
1290 1297
    std::istringstream line;
1291 1298

	
1292 1299
  public:
1293 1300

	
1294 1301
    /// \brief Constructor
1295 1302
    ///
1296 1303
    /// Construct an undirected graph reader, which reads from the given
1297 1304
    /// input stream.
1298 1305
    GraphReader(Graph& graph, std::istream& is = std::cin)
1299 1306
      : _is(&is), local_is(false), _graph(graph),
1300 1307
        _use_nodes(false), _use_edges(false),
1301 1308
        _skip_nodes(false), _skip_edges(false) {}
1302 1309

	
1303 1310
    /// \brief Constructor
1304 1311
    ///
1305 1312
    /// Construct an undirected graph reader, which reads from the given
1306 1313
    /// file.
1307 1314
    GraphReader(Graph& graph, const std::string& fn)
1308 1315
      : _is(new std::ifstream(fn.c_str())), local_is(true),
1309 1316
        _filename(fn), _graph(graph),
1310 1317
        _use_nodes(false), _use_edges(false),
1311 1318
        _skip_nodes(false), _skip_edges(false) {
1312 1319
      if (!(*_is)) {
1313 1320
        delete _is;
1314 1321
        throw IoError("Cannot open file", fn);
1315 1322
      }
1316 1323
    }
1317 1324

	
1318 1325
    /// \brief Constructor
1319 1326
    ///
1320 1327
    /// Construct an undirected graph reader, which reads from the given
1321 1328
    /// file.
1322 1329
    GraphReader(Graph& graph, const char* fn)
1323 1330
      : _is(new std::ifstream(fn)), local_is(true),
1324 1331
        _filename(fn), _graph(graph),
1325 1332
        _use_nodes(false), _use_edges(false),
1326 1333
        _skip_nodes(false), _skip_edges(false) {
1327 1334
      if (!(*_is)) {
1328 1335
        delete _is;
1329 1336
        throw IoError("Cannot open file", fn);
1330 1337
      }
1331 1338
    }
1332 1339

	
1333 1340
    /// \brief Destructor
1334 1341
    ~GraphReader() {
1335 1342
      for (typename NodeMaps::iterator it = _node_maps.begin();
1336 1343
           it != _node_maps.end(); ++it) {
1337 1344
        delete it->second;
1338 1345
      }
1339 1346

	
1340 1347
      for (typename EdgeMaps::iterator it = _edge_maps.begin();
1341 1348
           it != _edge_maps.end(); ++it) {
1342 1349
        delete it->second;
1343 1350
      }
1344 1351

	
1345 1352
      for (typename Attributes::iterator it = _attributes.begin();
1346 1353
           it != _attributes.end(); ++it) {
1347 1354
        delete it->second;
1348 1355
      }
1349 1356

	
1350 1357
      if (local_is) {
1351 1358
        delete _is;
1352 1359
      }
1353 1360

	
1354 1361
    }
1355 1362

	
1356 1363
  private:
1357 1364
    template <typename GR>
1358 1365
    friend GraphReader<GR> graphReader(GR& graph, std::istream& is);
1359 1366
    template <typename GR>
1360 1367
    friend GraphReader<GR> graphReader(GR& graph, const std::string& fn); 
1361 1368
    template <typename GR>
1362 1369
    friend GraphReader<GR> graphReader(GR& graph, const char *fn);
1363 1370

	
1364 1371
    GraphReader(GraphReader& other)
1365 1372
      : _is(other._is), local_is(other.local_is), _graph(other._graph),
1366 1373
        _use_nodes(other._use_nodes), _use_edges(other._use_edges),
1367 1374
        _skip_nodes(other._skip_nodes), _skip_edges(other._skip_edges) {
1368 1375

	
1369 1376
      other._is = 0;
1370 1377
      other.local_is = false;
1371 1378

	
1372 1379
      _node_index.swap(other._node_index);
1373 1380
      _edge_index.swap(other._edge_index);
1374 1381

	
1375 1382
      _node_maps.swap(other._node_maps);
1376 1383
      _edge_maps.swap(other._edge_maps);
1377 1384
      _attributes.swap(other._attributes);
1378 1385

	
1379 1386
      _nodes_caption = other._nodes_caption;
1380 1387
      _edges_caption = other._edges_caption;
1381 1388
      _attributes_caption = other._attributes_caption;
1382 1389

	
1383 1390
    }
1384 1391

	
1385 1392
    GraphReader& operator=(const GraphReader&);
1386 1393

	
1387 1394
  public:
1388 1395

	
1389 1396
    /// \name Reading rules
1390 1397
    /// @{
1391 1398

	
1392 1399
    /// \brief Node map reading rule
1393 1400
    ///
1394 1401
    /// Add a node map reading rule to the reader.
1395 1402
    template <typename Map>
1396 1403
    GraphReader& nodeMap(const std::string& caption, Map& map) {
1397 1404
      checkConcept<concepts::WriteMap<Node, typename Map::Value>, Map>();
1398 1405
      _reader_bits::MapStorageBase<Node>* storage =
1399 1406
        new _reader_bits::MapStorage<Node, Map>(map);
1400 1407
      _node_maps.push_back(std::make_pair(caption, storage));
1401 1408
      return *this;
1402 1409
    }
1403 1410

	
1404 1411
    /// \brief Node map reading rule
1405 1412
    ///
1406 1413
    /// Add a node map reading rule with specialized converter to the
1407 1414
    /// reader.
1408 1415
    template <typename Map, typename Converter>
1409 1416
    GraphReader& nodeMap(const std::string& caption, Map& map,
1410 1417
                           const Converter& converter = Converter()) {
1411 1418
      checkConcept<concepts::WriteMap<Node, typename Map::Value>, Map>();
1412 1419
      _reader_bits::MapStorageBase<Node>* storage =
1413 1420
        new _reader_bits::MapStorage<Node, Map, Converter>(map, converter);
1414 1421
      _node_maps.push_back(std::make_pair(caption, storage));
1415 1422
      return *this;
1416 1423
    }
1417 1424

	
1418 1425
    /// \brief Edge map reading rule
1419 1426
    ///
1420 1427
    /// Add an edge map reading rule to the reader.
1421 1428
    template <typename Map>
1422 1429
    GraphReader& edgeMap(const std::string& caption, Map& map) {
1423 1430
      checkConcept<concepts::WriteMap<Edge, typename Map::Value>, Map>();
1424 1431
      _reader_bits::MapStorageBase<Edge>* storage =
1425 1432
        new _reader_bits::MapStorage<Edge, Map>(map);
1426 1433
      _edge_maps.push_back(std::make_pair(caption, storage));
1427 1434
      return *this;
1428 1435
    }
1429 1436

	
1430 1437
    /// \brief Edge map reading rule
1431 1438
    ///
1432 1439
    /// Add an edge map reading rule with specialized converter to the
1433 1440
    /// reader.
1434 1441
    template <typename Map, typename Converter>
1435 1442
    GraphReader& edgeMap(const std::string& caption, Map& map,
1436 1443
                          const Converter& converter = Converter()) {
1437 1444
      checkConcept<concepts::WriteMap<Edge, typename Map::Value>, Map>();
1438 1445
      _reader_bits::MapStorageBase<Edge>* storage =
1439 1446
        new _reader_bits::MapStorage<Edge, Map, Converter>(map, converter);
1440 1447
      _edge_maps.push_back(std::make_pair(caption, storage));
1441 1448
      return *this;
1442 1449
    }
1443 1450

	
1444 1451
    /// \brief Arc map reading rule
1445 1452
    ///
1446 1453
    /// Add an arc map reading rule to the reader.
1447 1454
    template <typename Map>
1448 1455
    GraphReader& arcMap(const std::string& caption, Map& map) {
1449 1456
      checkConcept<concepts::WriteMap<Arc, typename Map::Value>, Map>();
1450 1457
      _reader_bits::MapStorageBase<Edge>* forward_storage =
1451 1458
        new _reader_bits::GraphArcMapStorage<Graph, true, Map>(_graph, map);
1452 1459
      _edge_maps.push_back(std::make_pair('+' + caption, forward_storage));
1453 1460
      _reader_bits::MapStorageBase<Edge>* backward_storage =
1454 1461
        new _reader_bits::GraphArcMapStorage<Graph, false, Map>(_graph, map);
1455 1462
      _edge_maps.push_back(std::make_pair('-' + caption, backward_storage));
1456 1463
      return *this;
1457 1464
    }
1458 1465

	
1459 1466
    /// \brief Arc map reading rule
1460 1467
    ///
1461 1468
    /// Add an arc map reading rule with specialized converter to the
1462 1469
    /// reader.
1463 1470
    template <typename Map, typename Converter>
1464 1471
    GraphReader& arcMap(const std::string& caption, Map& map,
1465 1472
                          const Converter& converter = Converter()) {
1466 1473
      checkConcept<concepts::WriteMap<Arc, typename Map::Value>, Map>();
1467 1474
      _reader_bits::MapStorageBase<Edge>* forward_storage =
1468 1475
        new _reader_bits::GraphArcMapStorage<Graph, true, Map, Converter>
1469 1476
        (_graph, map, converter);
1470 1477
      _edge_maps.push_back(std::make_pair('+' + caption, forward_storage));
1471 1478
      _reader_bits::MapStorageBase<Edge>* backward_storage =
1472 1479
        new _reader_bits::GraphArcMapStorage<Graph, false, Map, Converter>
1473 1480
        (_graph, map, converter);
1474 1481
      _edge_maps.push_back(std::make_pair('-' + caption, backward_storage));
1475 1482
      return *this;
1476 1483
    }
1477 1484

	
1478 1485
    /// \brief Attribute reading rule
1479 1486
    ///
1480 1487
    /// Add an attribute reading rule to the reader.
1481 1488
    template <typename Value>
1482 1489
    GraphReader& attribute(const std::string& caption, Value& value) {
1483 1490
      _reader_bits::ValueStorageBase* storage =
1484 1491
        new _reader_bits::ValueStorage<Value>(value);
1485 1492
      _attributes.insert(std::make_pair(caption, storage));
1486 1493
      return *this;
1487 1494
    }
1488 1495

	
1489 1496
    /// \brief Attribute reading rule
1490 1497
    ///
1491 1498
    /// Add an attribute reading rule with specialized converter to the
1492 1499
    /// reader.
1493 1500
    template <typename Value, typename Converter>
1494 1501
    GraphReader& attribute(const std::string& caption, Value& value,
1495 1502
                             const Converter& converter = Converter()) {
1496 1503
      _reader_bits::ValueStorageBase* storage =
1497 1504
        new _reader_bits::ValueStorage<Value, Converter>(value, converter);
1498 1505
      _attributes.insert(std::make_pair(caption, storage));
1499 1506
      return *this;
1500 1507
    }
1501 1508

	
1502 1509
    /// \brief Node reading rule
1503 1510
    ///
1504 1511
    /// Add a node reading rule to reader.
1505 1512
    GraphReader& node(const std::string& caption, Node& node) {
1506 1513
      typedef _reader_bits::MapLookUpConverter<Node> Converter;
1507 1514
      Converter converter(_node_index);
1508 1515
      _reader_bits::ValueStorageBase* storage =
1509 1516
        new _reader_bits::ValueStorage<Node, Converter>(node, converter);
1510 1517
      _attributes.insert(std::make_pair(caption, storage));
1511 1518
      return *this;
1512 1519
    }
1513 1520

	
1514 1521
    /// \brief Edge reading rule
1515 1522
    ///
1516 1523
    /// Add an edge reading rule to reader.
1517 1524
    GraphReader& edge(const std::string& caption, Edge& edge) {
1518 1525
      typedef _reader_bits::MapLookUpConverter<Edge> Converter;
1519 1526
      Converter converter(_edge_index);
1520 1527
      _reader_bits::ValueStorageBase* storage =
1521 1528
        new _reader_bits::ValueStorage<Edge, Converter>(edge, converter);
1522 1529
      _attributes.insert(std::make_pair(caption, storage));
1523 1530
      return *this;
1524 1531
    }
1525 1532

	
1526 1533
    /// \brief Arc reading rule
1527 1534
    ///
1528 1535
    /// Add an arc reading rule to reader.
1529 1536
    GraphReader& arc(const std::string& caption, Arc& arc) {
1530 1537
      typedef _reader_bits::GraphArcLookUpConverter<Graph> Converter;
1531 1538
      Converter converter(_graph, _edge_index);
1532 1539
      _reader_bits::ValueStorageBase* storage =
1533 1540
        new _reader_bits::ValueStorage<Arc, Converter>(arc, converter);
1534 1541
      _attributes.insert(std::make_pair(caption, storage));
1535 1542
      return *this;
1536 1543
    }
1537 1544

	
1538 1545
    /// @}
1539 1546

	
1540 1547
    /// \name Select section by name
1541 1548
    /// @{
1542 1549

	
1543 1550
    /// \brief Set \c \@nodes section to be read
1544 1551
    ///
1545 1552
    /// Set \c \@nodes section to be read.
1546 1553
    GraphReader& nodes(const std::string& caption) {
1547 1554
      _nodes_caption = caption;
1548 1555
      return *this;
1549 1556
    }
1550 1557

	
1551 1558
    /// \brief Set \c \@edges section to be read
1552 1559
    ///
1553 1560
    /// Set \c \@edges section to be read.
1554 1561
    GraphReader& edges(const std::string& caption) {
1555 1562
      _edges_caption = caption;
1556 1563
      return *this;
1557 1564
    }
1558 1565

	
1559 1566
    /// \brief Set \c \@attributes section to be read
1560 1567
    ///
1561 1568
    /// Set \c \@attributes section to be read.
1562 1569
    GraphReader& attributes(const std::string& caption) {
1563 1570
      _attributes_caption = caption;
1564 1571
      return *this;
1565 1572
    }
1566 1573

	
1567 1574
    /// @}
1568 1575

	
1569 1576
    /// \name Using previously constructed node or edge set
1570 1577
    /// @{
1571 1578

	
1572 1579
    /// \brief Use previously constructed node set
1573 1580
    ///
1574 1581
    /// Use previously constructed node set, and specify the node
1575 1582
    /// label map.
1576 1583
    template <typename Map>
1577 1584
    GraphReader& useNodes(const Map& map) {
1578 1585
      checkConcept<concepts::ReadMap<Node, typename Map::Value>, Map>();
1579 1586
      LEMON_ASSERT(!_use_nodes, "Multiple usage of useNodes() member");
1580 1587
      _use_nodes = true;
1581 1588
      _writer_bits::DefaultConverter<typename Map::Value> converter;
1582 1589
      for (NodeIt n(_graph); n != INVALID; ++n) {
1583 1590
        _node_index.insert(std::make_pair(converter(map[n]), n));
1584 1591
      }
1585 1592
      return *this;
1586 1593
    }
1587 1594

	
1588 1595
    /// \brief Use previously constructed node set
1589 1596
    ///
1590 1597
    /// Use previously constructed node set, and specify the node
1591 1598
    /// label map and a functor which converts the label map values to
1592 1599
    /// \c std::string.
1593 1600
    template <typename Map, typename Converter>
1594 1601
    GraphReader& useNodes(const Map& map,
1595 1602
                            const Converter& converter = Converter()) {
1596 1603
      checkConcept<concepts::ReadMap<Node, typename Map::Value>, Map>();
1597 1604
      LEMON_ASSERT(!_use_nodes, "Multiple usage of useNodes() member");
1598 1605
      _use_nodes = true;
1599 1606
      for (NodeIt n(_graph); n != INVALID; ++n) {
1600 1607
        _node_index.insert(std::make_pair(converter(map[n]), n));
1601 1608
      }
1602 1609
      return *this;
1603 1610
    }
1604 1611

	
1605 1612
    /// \brief Use previously constructed edge set
1606 1613
    ///
1607 1614
    /// Use previously constructed edge set, and specify the edge
1608 1615
    /// label map.
1609 1616
    template <typename Map>
1610 1617
    GraphReader& useEdges(const Map& map) {
1611 1618
      checkConcept<concepts::ReadMap<Edge, typename Map::Value>, Map>();
1612 1619
      LEMON_ASSERT(!_use_edges, "Multiple usage of useEdges() member");
1613 1620
      _use_edges = true;
1614 1621
      _writer_bits::DefaultConverter<typename Map::Value> converter;
1615 1622
      for (EdgeIt a(_graph); a != INVALID; ++a) {
1616 1623
        _edge_index.insert(std::make_pair(converter(map[a]), a));
1617 1624
      }
1618 1625
      return *this;
1619 1626
    }
1620 1627

	
1621 1628
    /// \brief Use previously constructed edge set
1622 1629
    ///
1623 1630
    /// Use previously constructed edge set, and specify the edge
1624 1631
    /// label map and a functor which converts the label map values to
1625 1632
    /// \c std::string.
1626 1633
    template <typename Map, typename Converter>
1627 1634
    GraphReader& useEdges(const Map& map,
1628 1635
                            const Converter& converter = Converter()) {
1629 1636
      checkConcept<concepts::ReadMap<Edge, typename Map::Value>, Map>();
1630 1637
      LEMON_ASSERT(!_use_edges, "Multiple usage of useEdges() member");
1631 1638
      _use_edges = true;
1632 1639
      for (EdgeIt a(_graph); a != INVALID; ++a) {
1633 1640
        _edge_index.insert(std::make_pair(converter(map[a]), a));
1634 1641
      }
1635 1642
      return *this;
1636 1643
    }
1637 1644

	
1638 1645
    /// \brief Skip the reading of node section
1639 1646
    ///
1640 1647
    /// Omit the reading of the node section. This implies that each node
1641 1648
    /// map reading rule will be abandoned, and the nodes of the graph
1642 1649
    /// will not be constructed, which usually cause that the edge set
1643 1650
    /// could not be read due to lack of node name
1644 1651
    /// could not be read due to lack of node name resolving.
1645 1652
    /// Therefore \c skipEdges() function should also be used, or
1646 1653
    /// \c useNodes() should be used to specify the label of the nodes.
1647 1654
    GraphReader& skipNodes() {
1648 1655
      LEMON_ASSERT(!_skip_nodes, "Skip nodes already set");
1649 1656
      _skip_nodes = true;
1650 1657
      return *this;
1651 1658
    }
1652 1659

	
1653 1660
    /// \brief Skip the reading of edge section
1654 1661
    ///
1655 1662
    /// Omit the reading of the edge section. This implies that each edge
1656 1663
    /// map reading rule will be abandoned, and the edges of the graph
1657 1664
    /// will not be constructed.
1658 1665
    GraphReader& skipEdges() {
1659 1666
      LEMON_ASSERT(!_skip_edges, "Skip edges already set");
1660 1667
      _skip_edges = true;
1661 1668
      return *this;
1662 1669
    }
1663 1670

	
1664 1671
    /// @}
1665 1672

	
1666 1673
  private:
1667 1674

	
1668 1675
    bool readLine() {
1669 1676
      std::string str;
1670 1677
      while(++line_num, std::getline(*_is, str)) {
1671 1678
        line.clear(); line.str(str);
1672 1679
        char c;
1673 1680
        if (line >> std::ws >> c && c != '#') {
1674 1681
          line.putback(c);
1675 1682
          return true;
1676 1683
        }
1677 1684
      }
1678 1685
      return false;
1679 1686
    }
1680 1687

	
1681 1688
    bool readSuccess() {
1682 1689
      return static_cast<bool>(*_is);
1683 1690
    }
1684 1691

	
1685 1692
    void skipSection() {
1686 1693
      char c;
1687 1694
      while (readSuccess() && line >> c && c != '@') {
1688 1695
        readLine();
1689 1696
      }
1690 1697
      line.putback(c);
1691 1698
    }
1692 1699

	
1693 1700
    void readNodes() {
1694 1701

	
1695 1702
      std::vector<int> map_index(_node_maps.size());
1696 1703
      int map_num, label_index;
1697 1704

	
1698 1705
      char c;
1699 1706
      if (!readLine() || !(line >> c) || c == '@') {
1700 1707
        if (readSuccess() && line) line.putback(c);
1701 1708
        if (!_node_maps.empty())
1702 1709
          throw FormatError("Cannot find map names");
1703 1710
        return;
1704 1711
      }
1705 1712
      line.putback(c);
1706 1713

	
1707 1714
      {
1708 1715
        std::map<std::string, int> maps;
1709 1716

	
1710 1717
        std::string map;
1711 1718
        int index = 0;
1712 1719
        while (_reader_bits::readToken(line, map)) {
1713 1720
          if (maps.find(map) != maps.end()) {
1714 1721
            std::ostringstream msg;
1715 1722
            msg << "Multiple occurence of node map: " << map;
1716 1723
            throw FormatError(msg.str());
1717 1724
          }
1718 1725
          maps.insert(std::make_pair(map, index));
1719 1726
          ++index;
1720 1727
        }
1721 1728

	
1722 1729
        for (int i = 0; i < static_cast<int>(_node_maps.size()); ++i) {
1723 1730
          std::map<std::string, int>::iterator jt =
1724 1731
            maps.find(_node_maps[i].first);
1725 1732
          if (jt == maps.end()) {
1726 1733
            std::ostringstream msg;
1727 1734
            msg << "Map not found: " << _node_maps[i].first;
1728 1735
            throw FormatError(msg.str());
1729 1736
          }
1730 1737
          map_index[i] = jt->second;
1731 1738
        }
1732 1739

	
1733 1740
        {
1734 1741
          std::map<std::string, int>::iterator jt = maps.find("label");
1735 1742
          if (jt != maps.end()) {
1736 1743
            label_index = jt->second;
1737 1744
          } else {
1738 1745
            label_index = -1;
1739 1746
          }
1740 1747
        }
1741 1748
        map_num = maps.size();
1742 1749
      }
1743 1750

	
1744 1751
      while (readLine() && line >> c && c != '@') {
1745 1752
        line.putback(c);
1746 1753

	
1747 1754
        std::vector<std::string> tokens(map_num);
1748 1755
        for (int i = 0; i < map_num; ++i) {
1749 1756
          if (!_reader_bits::readToken(line, tokens[i])) {
1750 1757
            std::ostringstream msg;
1751 1758
            msg << "Column not found (" << i + 1 << ")";
1752 1759
            throw FormatError(msg.str());
1753 1760
          }
1754 1761
        }
1755 1762
        if (line >> std::ws >> c)
1756 1763
          throw FormatError("Extra character at the end of line");
1757 1764

	
1758 1765
        Node n;
1759 1766
        if (!_use_nodes) {
1760 1767
          n = _graph.addNode();
1761 1768
          if (label_index != -1)
1762 1769
            _node_index.insert(std::make_pair(tokens[label_index], n));
1763 1770
        } else {
1764 1771
          if (label_index == -1)
1765 1772
            throw FormatError("Label map not found");
1766 1773
          typename std::map<std::string, Node>::iterator it =
1767 1774
            _node_index.find(tokens[label_index]);
1768 1775
          if (it == _node_index.end()) {
1769 1776
            std::ostringstream msg;
1770 1777
            msg << "Node with label not found: " << tokens[label_index];
1771 1778
            throw FormatError(msg.str());
1772 1779
          }
1773 1780
          n = it->second;
1774 1781
        }
1775 1782

	
1776 1783
        for (int i = 0; i < static_cast<int>(_node_maps.size()); ++i) {
1777 1784
          _node_maps[i].second->set(n, tokens[map_index[i]]);
1778 1785
        }
1779 1786

	
1780 1787
      }
1781 1788
      if (readSuccess()) {
1782 1789
        line.putback(c);
1783 1790
      }
1784 1791
    }
1785 1792

	
1786 1793
    void readEdges() {
1787 1794

	
1788 1795
      std::vector<int> map_index(_edge_maps.size());
1789 1796
      int map_num, label_index;
1790 1797

	
1791 1798
      char c;
1792 1799
      if (!readLine() || !(line >> c) || c == '@') {
1793 1800
        if (readSuccess() && line) line.putback(c);
1794 1801
        if (!_edge_maps.empty())
1795 1802
          throw FormatError("Cannot find map names");
1796 1803
        return;
1797 1804
      }
1798 1805
      line.putback(c);
1799 1806

	
1800 1807
      {
1801 1808
        std::map<std::string, int> maps;
1802 1809

	
1803 1810
        std::string map;
1804 1811
        int index = 0;
1805 1812
        while (_reader_bits::readToken(line, map)) {
1813
          if(map == "-") {
1814
              if(index!=0)
1815
                throw FormatError("'-' is not allowed as a map name");
1816
              else if (line >> std::ws >> c)
1817
                throw FormatError("Extra character at the end of line");
1818
              else break;
1819
            }
1806 1820
          if (maps.find(map) != maps.end()) {
1807 1821
            std::ostringstream msg;
1808 1822
            msg << "Multiple occurence of edge map: " << map;
1809 1823
            throw FormatError(msg.str());
1810 1824
          }
1811 1825
          maps.insert(std::make_pair(map, index));
1812 1826
          ++index;
1813 1827
        }
1814 1828

	
1815 1829
        for (int i = 0; i < static_cast<int>(_edge_maps.size()); ++i) {
1816 1830
          std::map<std::string, int>::iterator jt =
1817 1831
            maps.find(_edge_maps[i].first);
1818 1832
          if (jt == maps.end()) {
1819 1833
            std::ostringstream msg;
1820 1834
            msg << "Map not found: " << _edge_maps[i].first;
1821 1835
            throw FormatError(msg.str());
1822 1836
          }
1823 1837
          map_index[i] = jt->second;
1824 1838
        }
1825 1839

	
1826 1840
        {
1827 1841
          std::map<std::string, int>::iterator jt = maps.find("label");
1828 1842
          if (jt != maps.end()) {
1829 1843
            label_index = jt->second;
1830 1844
          } else {
1831 1845
            label_index = -1;
1832 1846
          }
1833 1847
        }
1834 1848
        map_num = maps.size();
1835 1849
      }
1836 1850

	
1837 1851
      while (readLine() && line >> c && c != '@') {
1838 1852
        line.putback(c);
1839 1853

	
1840 1854
        std::string source_token;
1841 1855
        std::string target_token;
1842 1856

	
1843 1857
        if (!_reader_bits::readToken(line, source_token))
1844 1858
          throw FormatError("Node u not found");
1845 1859

	
1846 1860
        if (!_reader_bits::readToken(line, target_token))
1847 1861
          throw FormatError("Node v not found");
1848 1862

	
1849 1863
        std::vector<std::string> tokens(map_num);
1850 1864
        for (int i = 0; i < map_num; ++i) {
1851 1865
          if (!_reader_bits::readToken(line, tokens[i])) {
1852 1866
            std::ostringstream msg;
1853 1867
            msg << "Column not found (" << i + 1 << ")";
1854 1868
            throw FormatError(msg.str());
1855 1869
          }
1856 1870
        }
1857 1871
        if (line >> std::ws >> c)
1858 1872
          throw FormatError("Extra character at the end of line");
1859 1873

	
1860 1874
        Edge e;
1861 1875
        if (!_use_edges) {
1862 1876

	
1863 1877
          typename NodeIndex::iterator it;
1864 1878

	
1865 1879
          it = _node_index.find(source_token);
1866 1880
          if (it == _node_index.end()) {
1867 1881
            std::ostringstream msg;
1868 1882
            msg << "Item not found: " << source_token;
1869 1883
            throw FormatError(msg.str());
1870 1884
          }
1871 1885
          Node source = it->second;
1872 1886

	
1873 1887
          it = _node_index.find(target_token);
1874 1888
          if (it == _node_index.end()) {
1875 1889
            std::ostringstream msg;
1876 1890
            msg << "Item not found: " << target_token;
1877 1891
            throw FormatError(msg.str());
1878 1892
          }
1879 1893
          Node target = it->second;
1880 1894

	
1881 1895
          e = _graph.addEdge(source, target);
1882 1896
          if (label_index != -1)
1883 1897
            _edge_index.insert(std::make_pair(tokens[label_index], e));
1884 1898
        } else {
1885 1899
          if (label_index == -1)
1886 1900
            throw FormatError("Label map not found");
1887 1901
          typename std::map<std::string, Edge>::iterator it =
1888 1902
            _edge_index.find(tokens[label_index]);
1889 1903
          if (it == _edge_index.end()) {
1890 1904
            std::ostringstream msg;
1891 1905
            msg << "Edge with label not found: " << tokens[label_index];
1892 1906
            throw FormatError(msg.str());
1893 1907
          }
1894 1908
          e = it->second;
1895 1909
        }
1896 1910

	
1897 1911
        for (int i = 0; i < static_cast<int>(_edge_maps.size()); ++i) {
1898 1912
          _edge_maps[i].second->set(e, tokens[map_index[i]]);
1899 1913
        }
1900 1914

	
1901 1915
      }
1902 1916
      if (readSuccess()) {
1903 1917
        line.putback(c);
1904 1918
      }
1905 1919
    }
1906 1920

	
1907 1921
    void readAttributes() {
1908 1922

	
1909 1923
      std::set<std::string> read_attr;
1910 1924

	
1911 1925
      char c;
1912 1926
      while (readLine() && line >> c && c != '@') {
1913 1927
        line.putback(c);
1914 1928

	
1915 1929
        std::string attr, token;
1916 1930
        if (!_reader_bits::readToken(line, attr))
1917 1931
          throw FormatError("Attribute name not found");
1918 1932
        if (!_reader_bits::readToken(line, token))
1919 1933
          throw FormatError("Attribute value not found");
1920 1934
        if (line >> c)
1921 1935
          throw FormatError("Extra character at the end of line");
1922 1936

	
1923 1937
        {
1924 1938
          std::set<std::string>::iterator it = read_attr.find(attr);
1925 1939
          if (it != read_attr.end()) {
1926 1940
            std::ostringstream msg;
1927 1941
            msg << "Multiple occurence of attribute: " << attr;
1928 1942
            throw FormatError(msg.str());
1929 1943
          }
1930 1944
          read_attr.insert(attr);
1931 1945
        }
1932 1946

	
1933 1947
        {
1934 1948
          typename Attributes::iterator it = _attributes.lower_bound(attr);
1935 1949
          while (it != _attributes.end() && it->first == attr) {
1936 1950
            it->second->set(token);
1937 1951
            ++it;
1938 1952
          }
1939 1953
        }
1940 1954

	
1941 1955
      }
1942 1956
      if (readSuccess()) {
1943 1957
        line.putback(c);
1944 1958
      }
1945 1959
      for (typename Attributes::iterator it = _attributes.begin();
1946 1960
           it != _attributes.end(); ++it) {
1947 1961
        if (read_attr.find(it->first) == read_attr.end()) {
1948 1962
          std::ostringstream msg;
1949 1963
          msg << "Attribute not found: " << it->first;
1950 1964
          throw FormatError(msg.str());
1951 1965
        }
1952 1966
      }
1953 1967
    }
1954 1968

	
1955 1969
  public:
1956 1970

	
1957 1971
    /// \name Execution of the reader
1958 1972
    /// @{
1959 1973

	
1960 1974
    /// \brief Start the batch processing
1961 1975
    ///
1962 1976
    /// This function starts the batch processing
1963 1977
    void run() {
1964 1978

	
1965 1979
      LEMON_ASSERT(_is != 0, "This reader assigned to an other reader");
1966 1980

	
1967 1981
      bool nodes_done = _skip_nodes;
1968 1982
      bool edges_done = _skip_edges;
1969 1983
      bool attributes_done = false;
1970 1984

	
1971 1985
      line_num = 0;
1972 1986
      readLine();
1973 1987
      skipSection();
1974 1988

	
1975 1989
      while (readSuccess()) {
1976 1990
        try {
1977 1991
          char c;
1978 1992
          std::string section, caption;
1979 1993
          line >> c;
1980 1994
          _reader_bits::readToken(line, section);
1981 1995
          _reader_bits::readToken(line, caption);
1982 1996

	
1983 1997
          if (line >> c)
1984 1998
            throw FormatError("Extra character at the end of line");
1985 1999

	
1986 2000
          if (section == "nodes" && !nodes_done) {
1987 2001
            if (_nodes_caption.empty() || _nodes_caption == caption) {
1988 2002
              readNodes();
1989 2003
              nodes_done = true;
1990 2004
            }
1991 2005
          } else if ((section == "edges" || section == "arcs") &&
1992 2006
                     !edges_done) {
1993 2007
            if (_edges_caption.empty() || _edges_caption == caption) {
1994 2008
              readEdges();
1995 2009
              edges_done = true;
1996 2010
            }
1997 2011
          } else if (section == "attributes" && !attributes_done) {
1998 2012
            if (_attributes_caption.empty() || _attributes_caption == caption) {
1999 2013
              readAttributes();
2000 2014
              attributes_done = true;
2001 2015
            }
2002 2016
          } else {
2003 2017
            readLine();
2004 2018
            skipSection();
2005 2019
          }
2006 2020
        } catch (FormatError& error) {
2007 2021
          error.line(line_num);
2008 2022
          error.file(_filename);
2009 2023
          throw;
2010 2024
        }
2011 2025
      }
2012 2026

	
2013 2027
      if (!nodes_done) {
2014 2028
        throw FormatError("Section @nodes not found");
2015 2029
      }
2016 2030

	
2017 2031
      if (!edges_done) {
2018 2032
        throw FormatError("Section @edges not found");
2019 2033
      }
2020 2034

	
2021 2035
      if (!attributes_done && !_attributes.empty()) {
2022 2036
        throw FormatError("Section @attributes not found");
2023 2037
      }
2024 2038

	
2025 2039
    }
2026 2040

	
2027 2041
    /// @}
2028 2042

	
2029 2043
  };
2030 2044

	
2031 2045
  /// \brief Return a \ref GraphReader class
2032 2046
  ///
2033 2047
  /// This function just returns a \ref GraphReader class.
2034 2048
  /// \relates GraphReader
2035 2049
  template <typename Graph>
2036 2050
  GraphReader<Graph> graphReader(Graph& graph, std::istream& is) {
2037 2051
    GraphReader<Graph> tmp(graph, is);
2038 2052
    return tmp;
2039 2053
  }
2040 2054

	
2041 2055
  /// \brief Return a \ref GraphReader class
2042 2056
  ///
2043 2057
  /// This function just returns a \ref GraphReader class.
2044 2058
  /// \relates GraphReader
2045 2059
  template <typename Graph>
2046 2060
  GraphReader<Graph> graphReader(Graph& graph, const std::string& fn) {
2047 2061
    GraphReader<Graph> tmp(graph, fn);
2048 2062
    return tmp;
2049 2063
  }
2050 2064

	
2051 2065
  /// \brief Return a \ref GraphReader class
2052 2066
  ///
2053 2067
  /// This function just returns a \ref GraphReader class.
2054 2068
  /// \relates GraphReader
2055 2069
  template <typename Graph>
2056 2070
  GraphReader<Graph> graphReader(Graph& graph, const char* fn) {
2057 2071
    GraphReader<Graph> tmp(graph, fn);
2058 2072
    return tmp;
2059 2073
  }
2060 2074

	
2061 2075
  class SectionReader;
2062 2076

	
2063 2077
  SectionReader sectionReader(std::istream& is);
2064 2078
  SectionReader sectionReader(const std::string& fn);
2065 2079
  SectionReader sectionReader(const char* fn);
2066 2080

	
2067 2081
  /// \ingroup lemon_io
2068 2082
  ///
2069 2083
  /// \brief Section reader class
2070 2084
  ///
2071 2085
  /// In the \ref lgf-format "LGF" file extra sections can be placed,
2072 2086
  /// which contain any data in arbitrary format. Such sections can be
2073 2087
  /// read with this class. A reading rule can be added to the class
2074 2088
  /// with two different functions. With the \c sectionLines() function a
2075 2089
  /// functor can process the section line-by-line, while with the \c
2076 2090
  /// sectionStream() member the section can be read from an input
2077 2091
  /// stream.
2078 2092
  class SectionReader {
2079 2093
  private:
2080 2094

	
2081 2095
    std::istream* _is;
2082 2096
    bool local_is;
2083 2097
    std::string _filename;
2084 2098

	
2085 2099
    typedef std::map<std::string, _reader_bits::Section*> Sections;
2086 2100
    Sections _sections;
2087 2101

	
2088 2102
    int line_num;
2089 2103
    std::istringstream line;
2090 2104

	
2091 2105
  public:
2092 2106

	
2093 2107
    /// \brief Constructor
2094 2108
    ///
2095 2109
    /// Construct a section reader, which reads from the given input
2096 2110
    /// stream.
2097 2111
    SectionReader(std::istream& is)
2098 2112
      : _is(&is), local_is(false) {}
2099 2113

	
2100 2114
    /// \brief Constructor
2101 2115
    ///
2102 2116
    /// Construct a section reader, which reads from the given file.
2103 2117
    SectionReader(const std::string& fn)
2104 2118
      : _is(new std::ifstream(fn.c_str())), local_is(true),
2105 2119
        _filename(fn) {
2106 2120
      if (!(*_is)) {
2107 2121
        delete _is;
2108 2122
        throw IoError("Cannot open file", fn);
2109 2123
      }
2110 2124
    }
2111 2125

	
2112 2126
    /// \brief Constructor
2113 2127
    ///
2114 2128
    /// Construct a section reader, which reads from the given file.
2115 2129
    SectionReader(const char* fn)
2116 2130
      : _is(new std::ifstream(fn)), local_is(true),
2117 2131
        _filename(fn) {
2118 2132
      if (!(*_is)) {
2119 2133
        delete _is;
2120 2134
        throw IoError("Cannot open file", fn);
2121 2135
      }
2122 2136
    }
2123 2137

	
2124 2138
    /// \brief Destructor
2125 2139
    ~SectionReader() {
2126 2140
      for (Sections::iterator it = _sections.begin();
2127 2141
           it != _sections.end(); ++it) {
2128 2142
        delete it->second;
2129 2143
      }
2130 2144

	
2131 2145
      if (local_is) {
2132 2146
        delete _is;
2133 2147
      }
2134 2148

	
2135 2149
    }
2136 2150

	
2137 2151
  private:
2138 2152

	
2139 2153
    friend SectionReader sectionReader(std::istream& is);
2140 2154
    friend SectionReader sectionReader(const std::string& fn);
2141 2155
    friend SectionReader sectionReader(const char* fn);
2142 2156

	
2143 2157
    SectionReader(SectionReader& other)
2144 2158
      : _is(other._is), local_is(other.local_is) {
2145 2159

	
2146 2160
      other._is = 0;
2147 2161
      other.local_is = false;
2148 2162

	
2149 2163
      _sections.swap(other._sections);
2150 2164
    }
2151 2165

	
2152 2166
    SectionReader& operator=(const SectionReader&);
2153 2167

	
2154 2168
  public:
2155 2169

	
2156 2170
    /// \name Section readers
2157 2171
    /// @{
2158 2172

	
2159 2173
    /// \brief Add a section processor with line oriented reading
2160 2174
    ///
2161 2175
    /// The first parameter is the type descriptor of the section, the
2162 2176
    /// second is a functor, which takes just one \c std::string
2163 2177
    /// parameter. At the reading process, each line of the section
2164 2178
    /// will be given to the functor object. However, the empty lines
2165 2179
    /// and the comment lines are filtered out, and the leading
2166 2180
    /// whitespaces are trimmed from each processed string.
2167 2181
    ///
2168 2182
    /// For example let's see a section, which contain several
2169 2183
    /// integers, which should be inserted into a vector.
2170 2184
    ///\code
2171 2185
    ///  @numbers
2172 2186
    ///  12 45 23
2173 2187
    ///  4
2174 2188
    ///  23 6
2175 2189
    ///\endcode
2176 2190
    ///
2177 2191
    /// The functor is implemented as a struct:
2178 2192
    ///\code
2179 2193
    ///  struct NumberSection {
2180 2194
    ///    std::vector<int>& _data;
2181 2195
    ///    NumberSection(std::vector<int>& data) : _data(data) {}
2182 2196
    ///    void operator()(const std::string& line) {
2183 2197
    ///      std::istringstream ls(line);
2184 2198
    ///      int value;
2185 2199
    ///      while (ls >> value) _data.push_back(value);
2186 2200
    ///    }
2187 2201
    ///  };
2188 2202
    ///
2189 2203
    ///  // ...
2190 2204
    ///
2191 2205
    ///  reader.sectionLines("numbers", NumberSection(vec));
2192 2206
    ///\endcode
2193 2207
    template <typename Functor>
2194 2208
    SectionReader& sectionLines(const std::string& type, Functor functor) {
2195 2209
      LEMON_ASSERT(!type.empty(), "Type is empty.");
2196 2210
      LEMON_ASSERT(_sections.find(type) == _sections.end(),
2197 2211
                   "Multiple reading of section.");
2198 2212
      _sections.insert(std::make_pair(type,
2199 2213
        new _reader_bits::LineSection<Functor>(functor)));
2200 2214
      return *this;
2201 2215
    }
2202 2216

	
2203 2217

	
2204 2218
    /// \brief Add a section processor with stream oriented reading
2205 2219
    ///
2206 2220
    /// The first parameter is the type of the section, the second is
2207 2221
    /// a functor, which takes an \c std::istream& and an \c int&
2208 2222
    /// parameter, the latter regard to the line number of stream. The
2209 2223
    /// functor can read the input while the section go on, and the
2210 2224
    /// line number should be modified accordingly.
2211 2225
    template <typename Functor>
2212 2226
    SectionReader& sectionStream(const std::string& type, Functor functor) {
2213 2227
      LEMON_ASSERT(!type.empty(), "Type is empty.");
2214 2228
      LEMON_ASSERT(_sections.find(type) == _sections.end(),
2215 2229
                   "Multiple reading of section.");
2216 2230
      _sections.insert(std::make_pair(type,
2217 2231
         new _reader_bits::StreamSection<Functor>(functor)));
2218 2232
      return *this;
2219 2233
    }
2220 2234

	
2221 2235
    /// @}
2222 2236

	
2223 2237
  private:
2224 2238

	
2225 2239
    bool readLine() {
2226 2240
      std::string str;
2227 2241
      while(++line_num, std::getline(*_is, str)) {
2228 2242
        line.clear(); line.str(str);
2229 2243
        char c;
2230 2244
        if (line >> std::ws >> c && c != '#') {
2231 2245
          line.putback(c);
2232 2246
          return true;
2233 2247
        }
2234 2248
      }
2235 2249
      return false;
2236 2250
    }
2237 2251

	
2238 2252
    bool readSuccess() {
2239 2253
      return static_cast<bool>(*_is);
2240 2254
    }
2241 2255

	
2242 2256
    void skipSection() {
2243 2257
      char c;
2244 2258
      while (readSuccess() && line >> c && c != '@') {
2245 2259
        readLine();
2246 2260
      }
2247 2261
      line.putback(c);
2248 2262
    }
2249 2263

	
2250 2264
  public:
2251 2265

	
2252 2266

	
2253 2267
    /// \name Execution of the reader
2254 2268
    /// @{
2255 2269

	
2256 2270
    /// \brief Start the batch processing
2257 2271
    ///
2258 2272
    /// This function starts the batch processing.
2259 2273
    void run() {
2260 2274

	
2261 2275
      LEMON_ASSERT(_is != 0, "This reader assigned to an other reader");
2262 2276

	
2263 2277
      std::set<std::string> extra_sections;
2264 2278

	
2265 2279
      line_num = 0;
2266 2280
      readLine();
2267 2281
      skipSection();
2268 2282

	
2269 2283
      while (readSuccess()) {
2270 2284
        try {
2271 2285
          char c;
2272 2286
          std::string section, caption;
2273 2287
          line >> c;
2274 2288
          _reader_bits::readToken(line, section);
2275 2289
          _reader_bits::readToken(line, caption);
2276 2290

	
2277 2291
          if (line >> c)
2278 2292
            throw FormatError("Extra character at the end of line");
2279 2293

	
2280 2294
          if (extra_sections.find(section) != extra_sections.end()) {
2281 2295
            std::ostringstream msg;
2282 2296
            msg << "Multiple occurence of section: " << section;
2283 2297
            throw FormatError(msg.str());
2284 2298
          }
2285 2299
          Sections::iterator it = _sections.find(section);
2286 2300
          if (it != _sections.end()) {
2287 2301
            extra_sections.insert(section);
2288 2302
            it->second->process(*_is, line_num);
2289 2303
          }
2290 2304
          readLine();
2291 2305
          skipSection();
2292 2306
        } catch (FormatError& error) {
2293 2307
          error.line(line_num);
2294 2308
          error.file(_filename);
2295 2309
          throw;
2296 2310
        }
2297 2311
      }
2298 2312
      for (Sections::iterator it = _sections.begin();
2299 2313
           it != _sections.end(); ++it) {
2300 2314
        if (extra_sections.find(it->first) == extra_sections.end()) {
2301 2315
          std::ostringstream os;
2302 2316
          os << "Cannot find section: " << it->first;
2303 2317
          throw FormatError(os.str());
2304 2318
        }
2305 2319
      }
2306 2320
    }
2307 2321

	
2308 2322
    /// @}
2309 2323

	
2310 2324
  };
2311 2325

	
2312 2326
  /// \brief Return a \ref SectionReader class
2313 2327
  ///
2314 2328
  /// This function just returns a \ref SectionReader class.
2315 2329
  /// \relates SectionReader
2316 2330
  inline SectionReader sectionReader(std::istream& is) {
2317 2331
    SectionReader tmp(is);
2318 2332
    return tmp;
2319 2333
  }
2320 2334

	
2321 2335
  /// \brief Return a \ref SectionReader class
2322 2336
  ///
2323 2337
  /// This function just returns a \ref SectionReader class.
2324 2338
  /// \relates SectionReader
2325 2339
  inline SectionReader sectionReader(const std::string& fn) {
2326 2340
    SectionReader tmp(fn);
2327 2341
    return tmp;
2328 2342
  }
2329 2343

	
2330 2344
  /// \brief Return a \ref SectionReader class
2331 2345
  ///
2332 2346
  /// This function just returns a \ref SectionReader class.
2333 2347
  /// \relates SectionReader
2334 2348
  inline SectionReader sectionReader(const char* fn) {
2335 2349
    SectionReader tmp(fn);
2336 2350
    return tmp;
2337 2351
  }
2338 2352

	
2339 2353
  /// \ingroup lemon_io
2340 2354
  ///
2341 2355
  /// \brief Reader for the contents of the \ref lgf-format "LGF" file
2342 2356
  ///
2343 2357
  /// This class can be used to read the sections, the map names and
2344 2358
  /// the attributes from a file. Usually, the LEMON programs know
2345 2359
  /// that, which type of graph, which maps and which attributes
2346 2360
  /// should be read from a file, but in general tools (like glemon)
2347 2361
  /// the contents of an LGF file should be guessed somehow. This class
2348 2362
  /// reads the graph and stores the appropriate information for
2349 2363
  /// reading the graph.
2350 2364
  ///
2351 2365
  ///\code
2352 2366
  /// LgfContents contents("graph.lgf");
2353 2367
  /// contents.run();
2354 2368
  ///
2355 2369
  /// // Does it contain any node section and arc section?
2356 2370
  /// if (contents.nodeSectionNum() == 0 || contents.arcSectionNum()) {
2357 2371
  ///   std::cerr << "Failure, cannot find graph." << std::endl;
2358 2372
  ///   return -1;
2359 2373
  /// }
2360 2374
  /// std::cout << "The name of the default node section: "
2361 2375
  ///           << contents.nodeSection(0) << std::endl;
2362 2376
  /// std::cout << "The number of the arc maps: "
2363 2377
  ///           << contents.arcMaps(0).size() << std::endl;
2364 2378
  /// std::cout << "The name of second arc map: "
2365 2379
  ///           << contents.arcMaps(0)[1] << std::endl;
2366 2380
  ///\endcode
2367 2381
  class LgfContents {
2368 2382
  private:
2369 2383

	
2370 2384
    std::istream* _is;
2371 2385
    bool local_is;
2372 2386

	
2373 2387
    std::vector<std::string> _node_sections;
2374 2388
    std::vector<std::string> _edge_sections;
2375 2389
    std::vector<std::string> _attribute_sections;
2376 2390
    std::vector<std::string> _extra_sections;
2377 2391

	
2378 2392
    std::vector<bool> _arc_sections;
2379 2393

	
2380 2394
    std::vector<std::vector<std::string> > _node_maps;
2381 2395
    std::vector<std::vector<std::string> > _edge_maps;
2382 2396

	
2383 2397
    std::vector<std::vector<std::string> > _attributes;
2384 2398

	
2385 2399

	
2386 2400
    int line_num;
2387 2401
    std::istringstream line;
2388 2402

	
2389 2403
  public:
2390 2404

	
2391 2405
    /// \brief Constructor
2392 2406
    ///
2393 2407
    /// Construct an \e LGF contents reader, which reads from the given
2394 2408
    /// input stream.
2395 2409
    LgfContents(std::istream& is)
2396 2410
      : _is(&is), local_is(false) {}
2397 2411

	
2398 2412
    /// \brief Constructor
2399 2413
    ///
2400 2414
    /// Construct an \e LGF contents reader, which reads from the given
2401 2415
    /// file.
2402 2416
    LgfContents(const std::string& fn)
2403 2417
      : _is(new std::ifstream(fn.c_str())), local_is(true) {
2404 2418
      if (!(*_is)) {
2405 2419
        delete _is;
2406 2420
        throw IoError("Cannot open file", fn);
2407 2421
      }
2408 2422
    }
2409 2423

	
2410 2424
    /// \brief Constructor
2411 2425
    ///
2412 2426
    /// Construct an \e LGF contents reader, which reads from the given
2413 2427
    /// file.
2414 2428
    LgfContents(const char* fn)
2415 2429
      : _is(new std::ifstream(fn)), local_is(true) {
2416 2430
      if (!(*_is)) {
2417 2431
        delete _is;
2418 2432
        throw IoError("Cannot open file", fn);
2419 2433
      }
2420 2434
    }
2421 2435

	
2422 2436
    /// \brief Destructor
2423 2437
    ~LgfContents() {
2424 2438
      if (local_is) delete _is;
2425 2439
    }
2426 2440

	
2427 2441
  private:
2428 2442

	
2429 2443
    LgfContents(const LgfContents&);
2430 2444
    LgfContents& operator=(const LgfContents&);
2431 2445

	
2432 2446
  public:
2433 2447

	
2434 2448

	
2435 2449
    /// \name Node sections
2436 2450
    /// @{
2437 2451

	
2438 2452
    /// \brief Gives back the number of node sections in the file.
2439 2453
    ///
2440 2454
    /// Gives back the number of node sections in the file.
2441 2455
    int nodeSectionNum() const {
2442 2456
      return _node_sections.size();
2443 2457
    }
2444 2458

	
2445 2459
    /// \brief Returns the node section name at the given position.
2446 2460
    ///
2447 2461
    /// Returns the node section name at the given position.
2448 2462
    const std::string& nodeSection(int i) const {
2449 2463
      return _node_sections[i];
2450 2464
    }
2451 2465

	
2452 2466
    /// \brief Gives back the node maps for the given section.
2453 2467
    ///
2454 2468
    /// Gives back the node maps for the given section.
2455 2469
    const std::vector<std::string>& nodeMapNames(int i) const {
2456 2470
      return _node_maps[i];
2457 2471
    }
2458 2472

	
2459 2473
    /// @}
2460 2474

	
2461 2475
    /// \name Arc/Edge sections
2462 2476
    /// @{
2463 2477

	
2464 2478
    /// \brief Gives back the number of arc/edge sections in the file.
2465 2479
    ///
2466 2480
    /// Gives back the number of arc/edge sections in the file.
2467 2481
    /// \note It is synonym of \c edgeSectionNum().
2468 2482
    int arcSectionNum() const {
2469 2483
      return _edge_sections.size();
2470 2484
    }
2471 2485

	
2472 2486
    /// \brief Returns the arc/edge section name at the given position.
2473 2487
    ///
2474 2488
    /// Returns the arc/edge section name at the given position.
2475 2489
    /// \note It is synonym of \c edgeSection().
2476 2490
    const std::string& arcSection(int i) const {
2477 2491
      return _edge_sections[i];
2478 2492
    }
2479 2493

	
2480 2494
    /// \brief Gives back the arc/edge maps for the given section.
2481 2495
    ///
2482 2496
    /// Gives back the arc/edge maps for the given section.
2483 2497
    /// \note It is synonym of \c edgeMapNames().
2484 2498
    const std::vector<std::string>& arcMapNames(int i) const {
2485 2499
      return _edge_maps[i];
2486 2500
    }
2487 2501

	
2488 2502
    /// @}
2489 2503

	
2490 2504
    /// \name Synonyms
2491 2505
    /// @{
2492 2506

	
2493 2507
    /// \brief Gives back the number of arc/edge sections in the file.
2494 2508
    ///
2495 2509
    /// Gives back the number of arc/edge sections in the file.
2496 2510
    /// \note It is synonym of \c arcSectionNum().
2497 2511
    int edgeSectionNum() const {
2498 2512
      return _edge_sections.size();
2499 2513
    }
2500 2514

	
2501 2515
    /// \brief Returns the section name at the given position.
2502 2516
    ///
2503 2517
    /// Returns the section name at the given position.
2504 2518
    /// \note It is synonym of \c arcSection().
2505 2519
    const std::string& edgeSection(int i) const {
2506 2520
      return _edge_sections[i];
2507 2521
    }
2508 2522

	
2509 2523
    /// \brief Gives back the edge maps for the given section.
2510 2524
    ///
2511 2525
    /// Gives back the edge maps for the given section.
2512 2526
    /// \note It is synonym of \c arcMapNames().
2513 2527
    const std::vector<std::string>& edgeMapNames(int i) const {
2514 2528
      return _edge_maps[i];
2515 2529
    }
2516 2530

	
2517 2531
    /// @}
2518 2532

	
2519 2533
    /// \name Attribute sections
2520 2534
    /// @{
2521 2535

	
2522 2536
    /// \brief Gives back the number of attribute sections in the file.
2523 2537
    ///
2524 2538
    /// Gives back the number of attribute sections in the file.
2525 2539
    int attributeSectionNum() const {
2526 2540
      return _attribute_sections.size();
2527 2541
    }
2528 2542

	
2529 2543
    /// \brief Returns the attribute section name at the given position.
2530 2544
    ///
2531 2545
    /// Returns the attribute section name at the given position.
2532 2546
    const std::string& attributeSectionNames(int i) const {
2533 2547
      return _attribute_sections[i];
2534 2548
    }
2535 2549

	
2536 2550
    /// \brief Gives back the attributes for the given section.
2537 2551
    ///
2538 2552
    /// Gives back the attributes for the given section.
2539 2553
    const std::vector<std::string>& attributes(int i) const {
2540 2554
      return _attributes[i];
2541 2555
    }
2542 2556

	
2543 2557
    /// @}
2544 2558

	
2545 2559
    /// \name Extra sections
2546 2560
    /// @{
2547 2561

	
2548 2562
    /// \brief Gives back the number of extra sections in the file.
2549 2563
    ///
2550 2564
    /// Gives back the number of extra sections in the file.
2551 2565
    int extraSectionNum() const {
2552 2566
      return _extra_sections.size();
2553 2567
    }
2554 2568

	
2555 2569
    /// \brief Returns the extra section type at the given position.
2556 2570
    ///
2557 2571
    /// Returns the section type at the given position.
2558 2572
    const std::string& extraSection(int i) const {
2559 2573
      return _extra_sections[i];
2560 2574
    }
2561 2575

	
2562 2576
    /// @}
2563 2577

	
2564 2578
  private:
2565 2579

	
2566 2580
    bool readLine() {
2567 2581
      std::string str;
2568 2582
      while(++line_num, std::getline(*_is, str)) {
2569 2583
        line.clear(); line.str(str);
2570 2584
        char c;
2571 2585
        if (line >> std::ws >> c && c != '#') {
2572 2586
          line.putback(c);
2573 2587
          return true;
Ignore white space 1536 line context
1 1
INCLUDE_DIRECTORIES(
2 2
  ${CMAKE_SOURCE_DIR}
3 3
  ${PROJECT_BINARY_DIR}
4 4
)
5 5

	
6 6
LINK_DIRECTORIES(${CMAKE_BINARY_DIR}/lemon)
7 7

	
8 8
SET(TESTS
9 9
  bfs_test
10 10
  counter_test
11 11
  dfs_test
12 12
  digraph_test
13 13
  dijkstra_test
14 14
  dim_test
15 15
  error_test
16 16
  graph_copy_test
17 17
  graph_test
18 18
  graph_utils_test
19 19
  heap_test
20 20
  kruskal_test
21
  lgf_test
21 22
  maps_test
22 23
  random_test
23 24
  path_test
24 25
  time_measure_test
25 26
  unionfind_test)
26 27

	
27 28
FOREACH(TEST_NAME ${TESTS})
28 29
  ADD_EXECUTABLE(${TEST_NAME} ${TEST_NAME}.cc)
29 30
  TARGET_LINK_LIBRARIES(${TEST_NAME} lemon)
30 31
  ADD_TEST(${TEST_NAME} ${TEST_NAME})
31 32
ENDFOREACH(TEST_NAME)
Ignore white space 6 line context
1 1
EXTRA_DIST += \
2 2
	test/CMakeLists.txt
3 3

	
4 4
noinst_HEADERS += \
5 5
	test/graph_test.h \
6 6
        test/test_tools.h
7 7

	
8 8
check_PROGRAMS += \
9 9
	test/bfs_test \
10 10
        test/counter_test \
11 11
	test/dfs_test \
12 12
	test/digraph_test \
13 13
	test/dijkstra_test \
14 14
        test/dim_test \
15 15
	test/error_test \
16 16
	test/graph_copy_test \
17 17
	test/graph_test \
18 18
	test/graph_utils_test \
19 19
	test/heap_test \
20 20
	test/kruskal_test \
21
	test/lgf_test \
21 22
        test/maps_test \
22 23
        test/random_test \
23 24
        test/path_test \
24 25
        test/test_tools_fail \
25 26
        test/test_tools_pass \
26 27
        test/time_measure_test \
27 28
	test/unionfind_test
28 29

	
29 30
TESTS += $(check_PROGRAMS)
30 31
XFAIL_TESTS += test/test_tools_fail$(EXEEXT)
31 32

	
32 33
test_bfs_test_SOURCES = test/bfs_test.cc
33 34
test_counter_test_SOURCES = test/counter_test.cc
34 35
test_dfs_test_SOURCES = test/dfs_test.cc
35 36
test_digraph_test_SOURCES = test/digraph_test.cc
36 37
test_dijkstra_test_SOURCES = test/dijkstra_test.cc
37 38
test_dim_test_SOURCES = test/dim_test.cc
38 39
test_error_test_SOURCES = test/error_test.cc
39 40
test_graph_copy_test_SOURCES = test/graph_copy_test.cc
40 41
test_graph_test_SOURCES = test/graph_test.cc
41 42
test_graph_utils_test_SOURCES = test/graph_utils_test.cc
42 43
test_heap_test_SOURCES = test/heap_test.cc
43 44
test_kruskal_test_SOURCES = test/kruskal_test.cc
45
test_lgf_test_SOURCES = test/lgf_test.cc
44 46
test_maps_test_SOURCES = test/maps_test.cc
45 47
test_path_test_SOURCES = test/path_test.cc
46 48
test_random_test_SOURCES = test/random_test.cc
47 49
test_test_tools_fail_SOURCES = test/test_tools_fail.cc
48 50
test_test_tools_pass_SOURCES = test/test_tools_pass.cc
49 51
test_time_measure_test_SOURCES = test/time_measure_test.cc
50 52
test_unionfind_test_SOURCES = test/unionfind_test.cc
0 comments (0 inline)