gravatar
alpar (Alpar Juttner)
alpar@cs.elte.hu
Merge #382 to branch 1.2
0 4 1
merge 1.2
4 files changed with 205 insertions and 8 deletions:
↑ Collapse diff ↑
Show white space 3072 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
}
Show white space 3072 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-2009
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
Show white space 3072 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-2010
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 _GR, bool _dir, typename _Map,
105 105
              typename _Converter = DefaultConverter<typename _Map::Value> >
106 106
    class GraphArcMapStorage : public MapStorageBase<typename _GR::Edge> {
107 107
    public:
108 108
      typedef _Map Map;
109 109
      typedef _Converter Converter;
110 110
      typedef _GR GR;
111 111
      typedef typename GR::Edge Item;
112 112
      static const bool dir = _dir;
113 113

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

	
119 119
    public:
120 120
      GraphArcMapStorage(const GR& 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 GR>
177 177
    struct GraphArcLookUpConverter {
178 178
      const GR& _graph;
179 179
      const std::map<std::string, typename GR::Edge>& _map;
180 180

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

	
186 186
      typename GR::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 GR::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 DGR>
391 391
  class DigraphReader;
392 392

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

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

	
454 454
    typedef DGR Digraph;
455 455

	
456 456
  private:
457 457

	
458 458
    TEMPLATE_DIGRAPH_TYPEDEFS(DGR);
459 459

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

	
464 464
    DGR& _digraph;
465 465

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

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

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

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

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

	
487 487
    bool _use_nodes;
488 488
    bool _use_arcs;
489 489

	
490 490
    bool _skip_nodes;
491 491
    bool _skip_arcs;
492 492

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

	
496 496
  public:
497 497

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

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

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

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

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

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

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

	
558 558
    }
559 559

	
560 560
  private:
561 561

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

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

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

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

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

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

	
589 589
    }
590 590

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

	
593 593
  public:
594 594

	
595 595
    /// \name Reading Rules
596 596
    /// @{
597 597

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

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

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

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

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

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

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

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

	
698 698
    /// @}
699 699

	
700 700
    /// \name Select Section by Name
701 701
    /// @{
702 702

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

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

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

	
727 727
    /// @}
728 728

	
729 729
    /// \name Using Previously Constructed Node or Arc Set
730 730
    /// @{
731 731

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

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

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

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

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

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

	
823 823
    /// @}
824 824

	
825 825
  private:
826 826

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

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

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

	
854 854
    void readNodes() {
855 855

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

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

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

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

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

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

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

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

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

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

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

	
947 947
    void readArcs() {
948 948

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

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

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

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

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

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

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

	
1001 1008
        std::string source_token;
1002 1009
        std::string target_token;
1003 1010

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

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

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

	
1021 1028
        Arc a;
1022 1029
        if (!_use_arcs) {
1023 1030

	
1024 1031
          typename NodeIndex::iterator it;
1025 1032

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

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

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

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

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

	
1068 1075
    void readAttributes() {
1069 1076

	
1070 1077
      std::set<std::string> read_attr;
1071 1078

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

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

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

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

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

	
1116 1123
  public:
1117 1124

	
1118 1125
    /// \name Execution of the Reader
1119 1126
    /// @{
1120 1127

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

	
1127 1134
      bool nodes_done = _skip_nodes;
1128 1135
      bool arcs_done = _skip_arcs;
1129 1136
      bool attributes_done = false;
1130 1137

	
1131 1138
      line_num = 0;
1132 1139
      readLine();
1133 1140
      skipSection();
1134 1141

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

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

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

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

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

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

	
1185 1192
    }
1186 1193

	
1187 1194
    /// @}
1188 1195

	
1189 1196
  };
1190 1197

	
1191 1198
  /// \ingroup lemon_io
1192 1199
  ///
1193 1200
  /// \brief Return a \ref DigraphReader class
1194 1201
  ///
1195 1202
  /// This function just returns a \ref DigraphReader class.
1196 1203
  ///
1197 1204
  /// With this function a digraph can be read from an
1198 1205
  /// \ref lgf-format "LGF" file or input stream with several maps and
1199 1206
  /// attributes. For example, there is network flow problem on a
1200 1207
  /// digraph, i.e. a digraph with a \e capacity map on the arcs and
1201 1208
  /// \e source and \e target nodes. This digraph can be read with the
1202 1209
  /// following code:
1203 1210
  ///
1204 1211
  ///\code
1205 1212
  ///ListDigraph digraph;
1206 1213
  ///ListDigraph::ArcMap<int> cm(digraph);
1207 1214
  ///ListDigraph::Node src, trg;
1208 1215
  ///digraphReader(digraph, std::cin).
1209 1216
  ///  arcMap("capacity", cap).
1210 1217
  ///  node("source", src).
1211 1218
  ///  node("target", trg).
1212 1219
  ///  run();
1213 1220
  ///\endcode
1214 1221
  ///
1215 1222
  /// For a complete documentation, please see the \ref DigraphReader
1216 1223
  /// class documentation.
1217 1224
  /// \warning Don't forget to put the \ref DigraphReader::run() "run()"
1218 1225
  /// to the end of the parameter list.
1219 1226
  /// \relates DigraphReader
1220 1227
  /// \sa digraphReader(TDGR& digraph, const std::string& fn)
1221 1228
  /// \sa digraphReader(TDGR& digraph, const char* fn)
1222 1229
  template <typename TDGR>
1223 1230
  DigraphReader<TDGR> digraphReader(TDGR& digraph, std::istream& is) {
1224 1231
    DigraphReader<TDGR> tmp(digraph, is);
1225 1232
    return tmp;
1226 1233
  }
1227 1234

	
1228 1235
  /// \brief Return a \ref DigraphReader class
1229 1236
  ///
1230 1237
  /// This function just returns a \ref DigraphReader class.
1231 1238
  /// \relates DigraphReader
1232 1239
  /// \sa digraphReader(TDGR& digraph, std::istream& is)
1233 1240
  template <typename TDGR>
1234 1241
  DigraphReader<TDGR> digraphReader(TDGR& digraph, const std::string& fn) {
1235 1242
    DigraphReader<TDGR> tmp(digraph, fn);
1236 1243
    return tmp;
1237 1244
  }
1238 1245

	
1239 1246
  /// \brief Return a \ref DigraphReader class
1240 1247
  ///
1241 1248
  /// This function just returns a \ref DigraphReader class.
1242 1249
  /// \relates DigraphReader
1243 1250
  /// \sa digraphReader(TDGR& digraph, std::istream& is)
1244 1251
  template <typename TDGR>
1245 1252
  DigraphReader<TDGR> digraphReader(TDGR& digraph, const char* fn) {
1246 1253
    DigraphReader<TDGR> tmp(digraph, fn);
1247 1254
    return tmp;
1248 1255
  }
1249 1256

	
1250 1257
  template <typename GR>
1251 1258
  class GraphReader;
1252 1259

	
1253 1260
  template <typename TGR>
1254 1261
  GraphReader<TGR> graphReader(TGR& graph, std::istream& is = std::cin);
1255 1262
  template <typename TGR>
1256 1263
  GraphReader<TGR> graphReader(TGR& graph, const std::string& fn);
1257 1264
  template <typename TGR>
1258 1265
  GraphReader<TGR> graphReader(TGR& graph, const char *fn);
1259 1266

	
1260 1267
  /// \ingroup lemon_io
1261 1268
  ///
1262 1269
  /// \brief \ref lgf-format "LGF" reader for undirected graphs
1263 1270
  ///
1264 1271
  /// This utility reads an \ref lgf-format "LGF" file.
1265 1272
  ///
1266 1273
  /// It can be used almost the same way as \c DigraphReader.
1267 1274
  /// The only difference is that this class can handle edges and
1268 1275
  /// edge maps as well as arcs and arc maps.
1269 1276
  ///
1270 1277
  /// The columns in the \c \@edges (or \c \@arcs) section are the
1271 1278
  /// edge maps. However, if there are two maps with the same name
1272 1279
  /// prefixed with \c '+' and \c '-', then these can be read into an
1273 1280
  /// arc map.  Similarly, an attribute can be read into an arc, if
1274 1281
  /// it's value is an edge label prefixed with \c '+' or \c '-'.
1275 1282
  template <typename GR>
1276 1283
  class GraphReader {
1277 1284
  public:
1278 1285

	
1279 1286
    typedef GR Graph;
1280 1287

	
1281 1288
  private:
1282 1289

	
1283 1290
    TEMPLATE_GRAPH_TYPEDEFS(GR);
1284 1291

	
1285 1292
    std::istream* _is;
1286 1293
    bool local_is;
1287 1294
    std::string _filename;
1288 1295

	
1289 1296
    GR& _graph;
1290 1297

	
1291 1298
    std::string _nodes_caption;
1292 1299
    std::string _edges_caption;
1293 1300
    std::string _attributes_caption;
1294 1301

	
1295 1302
    typedef std::map<std::string, Node> NodeIndex;
1296 1303
    NodeIndex _node_index;
1297 1304
    typedef std::map<std::string, Edge> EdgeIndex;
1298 1305
    EdgeIndex _edge_index;
1299 1306

	
1300 1307
    typedef std::vector<std::pair<std::string,
1301 1308
      _reader_bits::MapStorageBase<Node>*> > NodeMaps;
1302 1309
    NodeMaps _node_maps;
1303 1310

	
1304 1311
    typedef std::vector<std::pair<std::string,
1305 1312
      _reader_bits::MapStorageBase<Edge>*> > EdgeMaps;
1306 1313
    EdgeMaps _edge_maps;
1307 1314

	
1308 1315
    typedef std::multimap<std::string, _reader_bits::ValueStorageBase*>
1309 1316
      Attributes;
1310 1317
    Attributes _attributes;
1311 1318

	
1312 1319
    bool _use_nodes;
1313 1320
    bool _use_edges;
1314 1321

	
1315 1322
    bool _skip_nodes;
1316 1323
    bool _skip_edges;
1317 1324

	
1318 1325
    int line_num;
1319 1326
    std::istringstream line;
1320 1327

	
1321 1328
  public:
1322 1329

	
1323 1330
    /// \brief Constructor
1324 1331
    ///
1325 1332
    /// Construct an undirected graph reader, which reads from the given
1326 1333
    /// input stream.
1327 1334
    GraphReader(GR& graph, std::istream& is = std::cin)
1328 1335
      : _is(&is), local_is(false), _graph(graph),
1329 1336
        _use_nodes(false), _use_edges(false),
1330 1337
        _skip_nodes(false), _skip_edges(false) {}
1331 1338

	
1332 1339
    /// \brief Constructor
1333 1340
    ///
1334 1341
    /// Construct an undirected graph reader, which reads from the given
1335 1342
    /// file.
1336 1343
    GraphReader(GR& graph, const std::string& fn)
1337 1344
      : _is(new std::ifstream(fn.c_str())), local_is(true),
1338 1345
        _filename(fn), _graph(graph),
1339 1346
        _use_nodes(false), _use_edges(false),
1340 1347
        _skip_nodes(false), _skip_edges(false) {
1341 1348
      if (!(*_is)) {
1342 1349
        delete _is;
1343 1350
        throw IoError("Cannot open file", fn);
1344 1351
      }
1345 1352
    }
1346 1353

	
1347 1354
    /// \brief Constructor
1348 1355
    ///
1349 1356
    /// Construct an undirected graph reader, which reads from the given
1350 1357
    /// file.
1351 1358
    GraphReader(GR& graph, const char* fn)
1352 1359
      : _is(new std::ifstream(fn)), local_is(true),
1353 1360
        _filename(fn), _graph(graph),
1354 1361
        _use_nodes(false), _use_edges(false),
1355 1362
        _skip_nodes(false), _skip_edges(false) {
1356 1363
      if (!(*_is)) {
1357 1364
        delete _is;
1358 1365
        throw IoError("Cannot open file", fn);
1359 1366
      }
1360 1367
    }
1361 1368

	
1362 1369
    /// \brief Destructor
1363 1370
    ~GraphReader() {
1364 1371
      for (typename NodeMaps::iterator it = _node_maps.begin();
1365 1372
           it != _node_maps.end(); ++it) {
1366 1373
        delete it->second;
1367 1374
      }
1368 1375

	
1369 1376
      for (typename EdgeMaps::iterator it = _edge_maps.begin();
1370 1377
           it != _edge_maps.end(); ++it) {
1371 1378
        delete it->second;
1372 1379
      }
1373 1380

	
1374 1381
      for (typename Attributes::iterator it = _attributes.begin();
1375 1382
           it != _attributes.end(); ++it) {
1376 1383
        delete it->second;
1377 1384
      }
1378 1385

	
1379 1386
      if (local_is) {
1380 1387
        delete _is;
1381 1388
      }
1382 1389

	
1383 1390
    }
1384 1391

	
1385 1392
  private:
1386 1393
    template <typename TGR>
1387 1394
    friend GraphReader<TGR> graphReader(TGR& graph, std::istream& is);
1388 1395
    template <typename TGR>
1389 1396
    friend GraphReader<TGR> graphReader(TGR& graph, const std::string& fn);
1390 1397
    template <typename TGR>
1391 1398
    friend GraphReader<TGR> graphReader(TGR& graph, const char *fn);
1392 1399

	
1393 1400
    GraphReader(GraphReader& other)
1394 1401
      : _is(other._is), local_is(other.local_is), _graph(other._graph),
1395 1402
        _use_nodes(other._use_nodes), _use_edges(other._use_edges),
1396 1403
        _skip_nodes(other._skip_nodes), _skip_edges(other._skip_edges) {
1397 1404

	
1398 1405
      other._is = 0;
1399 1406
      other.local_is = false;
1400 1407

	
1401 1408
      _node_index.swap(other._node_index);
1402 1409
      _edge_index.swap(other._edge_index);
1403 1410

	
1404 1411
      _node_maps.swap(other._node_maps);
1405 1412
      _edge_maps.swap(other._edge_maps);
1406 1413
      _attributes.swap(other._attributes);
1407 1414

	
1408 1415
      _nodes_caption = other._nodes_caption;
1409 1416
      _edges_caption = other._edges_caption;
1410 1417
      _attributes_caption = other._attributes_caption;
1411 1418

	
1412 1419
    }
1413 1420

	
1414 1421
    GraphReader& operator=(const GraphReader&);
1415 1422

	
1416 1423
  public:
1417 1424

	
1418 1425
    /// \name Reading Rules
1419 1426
    /// @{
1420 1427

	
1421 1428
    /// \brief Node map reading rule
1422 1429
    ///
1423 1430
    /// Add a node map reading rule to the reader.
1424 1431
    template <typename Map>
1425 1432
    GraphReader& nodeMap(const std::string& caption, Map& map) {
1426 1433
      checkConcept<concepts::WriteMap<Node, typename Map::Value>, Map>();
1427 1434
      _reader_bits::MapStorageBase<Node>* storage =
1428 1435
        new _reader_bits::MapStorage<Node, Map>(map);
1429 1436
      _node_maps.push_back(std::make_pair(caption, storage));
1430 1437
      return *this;
1431 1438
    }
1432 1439

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

	
1447 1454
    /// \brief Edge map reading rule
1448 1455
    ///
1449 1456
    /// Add an edge map reading rule to the reader.
1450 1457
    template <typename Map>
1451 1458
    GraphReader& edgeMap(const std::string& caption, Map& map) {
1452 1459
      checkConcept<concepts::WriteMap<Edge, typename Map::Value>, Map>();
1453 1460
      _reader_bits::MapStorageBase<Edge>* storage =
1454 1461
        new _reader_bits::MapStorage<Edge, Map>(map);
1455 1462
      _edge_maps.push_back(std::make_pair(caption, storage));
1456 1463
      return *this;
1457 1464
    }
1458 1465

	
1459 1466
    /// \brief Edge map reading rule
1460 1467
    ///
1461 1468
    /// Add an edge map reading rule with specialized converter to the
1462 1469
    /// reader.
1463 1470
    template <typename Map, typename Converter>
1464 1471
    GraphReader& edgeMap(const std::string& caption, Map& map,
1465 1472
                          const Converter& converter = Converter()) {
1466 1473
      checkConcept<concepts::WriteMap<Edge, typename Map::Value>, Map>();
1467 1474
      _reader_bits::MapStorageBase<Edge>* storage =
1468 1475
        new _reader_bits::MapStorage<Edge, Map, Converter>(map, converter);
1469 1476
      _edge_maps.push_back(std::make_pair(caption, storage));
1470 1477
      return *this;
1471 1478
    }
1472 1479

	
1473 1480
    /// \brief Arc map reading rule
1474 1481
    ///
1475 1482
    /// Add an arc map reading rule to the reader.
1476 1483
    template <typename Map>
1477 1484
    GraphReader& arcMap(const std::string& caption, Map& map) {
1478 1485
      checkConcept<concepts::WriteMap<Arc, typename Map::Value>, Map>();
1479 1486
      _reader_bits::MapStorageBase<Edge>* forward_storage =
1480 1487
        new _reader_bits::GraphArcMapStorage<Graph, true, Map>(_graph, map);
1481 1488
      _edge_maps.push_back(std::make_pair('+' + caption, forward_storage));
1482 1489
      _reader_bits::MapStorageBase<Edge>* backward_storage =
1483 1490
        new _reader_bits::GraphArcMapStorage<GR, false, Map>(_graph, map);
1484 1491
      _edge_maps.push_back(std::make_pair('-' + caption, backward_storage));
1485 1492
      return *this;
1486 1493
    }
1487 1494

	
1488 1495
    /// \brief Arc map reading rule
1489 1496
    ///
1490 1497
    /// Add an arc map reading rule with specialized converter to the
1491 1498
    /// reader.
1492 1499
    template <typename Map, typename Converter>
1493 1500
    GraphReader& arcMap(const std::string& caption, Map& map,
1494 1501
                          const Converter& converter = Converter()) {
1495 1502
      checkConcept<concepts::WriteMap<Arc, typename Map::Value>, Map>();
1496 1503
      _reader_bits::MapStorageBase<Edge>* forward_storage =
1497 1504
        new _reader_bits::GraphArcMapStorage<GR, true, Map, Converter>
1498 1505
        (_graph, map, converter);
1499 1506
      _edge_maps.push_back(std::make_pair('+' + caption, forward_storage));
1500 1507
      _reader_bits::MapStorageBase<Edge>* backward_storage =
1501 1508
        new _reader_bits::GraphArcMapStorage<GR, false, Map, Converter>
1502 1509
        (_graph, map, converter);
1503 1510
      _edge_maps.push_back(std::make_pair('-' + caption, backward_storage));
1504 1511
      return *this;
1505 1512
    }
1506 1513

	
1507 1514
    /// \brief Attribute reading rule
1508 1515
    ///
1509 1516
    /// Add an attribute reading rule to the reader.
1510 1517
    template <typename Value>
1511 1518
    GraphReader& attribute(const std::string& caption, Value& value) {
1512 1519
      _reader_bits::ValueStorageBase* storage =
1513 1520
        new _reader_bits::ValueStorage<Value>(value);
1514 1521
      _attributes.insert(std::make_pair(caption, storage));
1515 1522
      return *this;
1516 1523
    }
1517 1524

	
1518 1525
    /// \brief Attribute reading rule
1519 1526
    ///
1520 1527
    /// Add an attribute reading rule with specialized converter to the
1521 1528
    /// reader.
1522 1529
    template <typename Value, typename Converter>
1523 1530
    GraphReader& attribute(const std::string& caption, Value& value,
1524 1531
                             const Converter& converter = Converter()) {
1525 1532
      _reader_bits::ValueStorageBase* storage =
1526 1533
        new _reader_bits::ValueStorage<Value, Converter>(value, converter);
1527 1534
      _attributes.insert(std::make_pair(caption, storage));
1528 1535
      return *this;
1529 1536
    }
1530 1537

	
1531 1538
    /// \brief Node reading rule
1532 1539
    ///
1533 1540
    /// Add a node reading rule to reader.
1534 1541
    GraphReader& node(const std::string& caption, Node& node) {
1535 1542
      typedef _reader_bits::MapLookUpConverter<Node> Converter;
1536 1543
      Converter converter(_node_index);
1537 1544
      _reader_bits::ValueStorageBase* storage =
1538 1545
        new _reader_bits::ValueStorage<Node, Converter>(node, converter);
1539 1546
      _attributes.insert(std::make_pair(caption, storage));
1540 1547
      return *this;
1541 1548
    }
1542 1549

	
1543 1550
    /// \brief Edge reading rule
1544 1551
    ///
1545 1552
    /// Add an edge reading rule to reader.
1546 1553
    GraphReader& edge(const std::string& caption, Edge& edge) {
1547 1554
      typedef _reader_bits::MapLookUpConverter<Edge> Converter;
1548 1555
      Converter converter(_edge_index);
1549 1556
      _reader_bits::ValueStorageBase* storage =
1550 1557
        new _reader_bits::ValueStorage<Edge, Converter>(edge, converter);
1551 1558
      _attributes.insert(std::make_pair(caption, storage));
1552 1559
      return *this;
1553 1560
    }
1554 1561

	
1555 1562
    /// \brief Arc reading rule
1556 1563
    ///
1557 1564
    /// Add an arc reading rule to reader.
1558 1565
    GraphReader& arc(const std::string& caption, Arc& arc) {
1559 1566
      typedef _reader_bits::GraphArcLookUpConverter<GR> Converter;
1560 1567
      Converter converter(_graph, _edge_index);
1561 1568
      _reader_bits::ValueStorageBase* storage =
1562 1569
        new _reader_bits::ValueStorage<Arc, Converter>(arc, converter);
1563 1570
      _attributes.insert(std::make_pair(caption, storage));
1564 1571
      return *this;
1565 1572
    }
1566 1573

	
1567 1574
    /// @}
1568 1575

	
1569 1576
    /// \name Select Section by Name
1570 1577
    /// @{
1571 1578

	
1572 1579
    /// \brief Set \c \@nodes section to be read
1573 1580
    ///
1574 1581
    /// Set \c \@nodes section to be read.
1575 1582
    GraphReader& nodes(const std::string& caption) {
1576 1583
      _nodes_caption = caption;
1577 1584
      return *this;
1578 1585
    }
1579 1586

	
1580 1587
    /// \brief Set \c \@edges section to be read
1581 1588
    ///
1582 1589
    /// Set \c \@edges section to be read.
1583 1590
    GraphReader& edges(const std::string& caption) {
1584 1591
      _edges_caption = caption;
1585 1592
      return *this;
1586 1593
    }
1587 1594

	
1588 1595
    /// \brief Set \c \@attributes section to be read
1589 1596
    ///
1590 1597
    /// Set \c \@attributes section to be read.
1591 1598
    GraphReader& attributes(const std::string& caption) {
1592 1599
      _attributes_caption = caption;
1593 1600
      return *this;
1594 1601
    }
1595 1602

	
1596 1603
    /// @}
1597 1604

	
1598 1605
    /// \name Using Previously Constructed Node or Edge Set
1599 1606
    /// @{
1600 1607

	
1601 1608
    /// \brief Use previously constructed node set
1602 1609
    ///
1603 1610
    /// Use previously constructed node set, and specify the node
1604 1611
    /// label map.
1605 1612
    template <typename Map>
1606 1613
    GraphReader& useNodes(const Map& map) {
1607 1614
      checkConcept<concepts::ReadMap<Node, typename Map::Value>, Map>();
1608 1615
      LEMON_ASSERT(!_use_nodes, "Multiple usage of useNodes() member");
1609 1616
      _use_nodes = true;
1610 1617
      _writer_bits::DefaultConverter<typename Map::Value> converter;
1611 1618
      for (NodeIt n(_graph); n != INVALID; ++n) {
1612 1619
        _node_index.insert(std::make_pair(converter(map[n]), n));
1613 1620
      }
1614 1621
      return *this;
1615 1622
    }
1616 1623

	
1617 1624
    /// \brief Use previously constructed node set
1618 1625
    ///
1619 1626
    /// Use previously constructed node set, and specify the node
1620 1627
    /// label map and a functor which converts the label map values to
1621 1628
    /// \c std::string.
1622 1629
    template <typename Map, typename Converter>
1623 1630
    GraphReader& useNodes(const Map& map,
1624 1631
                            const Converter& converter = Converter()) {
1625 1632
      checkConcept<concepts::ReadMap<Node, typename Map::Value>, Map>();
1626 1633
      LEMON_ASSERT(!_use_nodes, "Multiple usage of useNodes() member");
1627 1634
      _use_nodes = true;
1628 1635
      for (NodeIt n(_graph); n != INVALID; ++n) {
1629 1636
        _node_index.insert(std::make_pair(converter(map[n]), n));
1630 1637
      }
1631 1638
      return *this;
1632 1639
    }
1633 1640

	
1634 1641
    /// \brief Use previously constructed edge set
1635 1642
    ///
1636 1643
    /// Use previously constructed edge set, and specify the edge
1637 1644
    /// label map.
1638 1645
    template <typename Map>
1639 1646
    GraphReader& useEdges(const Map& map) {
1640 1647
      checkConcept<concepts::ReadMap<Edge, typename Map::Value>, Map>();
1641 1648
      LEMON_ASSERT(!_use_edges, "Multiple usage of useEdges() member");
1642 1649
      _use_edges = true;
1643 1650
      _writer_bits::DefaultConverter<typename Map::Value> converter;
1644 1651
      for (EdgeIt a(_graph); a != INVALID; ++a) {
1645 1652
        _edge_index.insert(std::make_pair(converter(map[a]), a));
1646 1653
      }
1647 1654
      return *this;
1648 1655
    }
1649 1656

	
1650 1657
    /// \brief Use previously constructed edge set
1651 1658
    ///
1652 1659
    /// Use previously constructed edge set, and specify the edge
1653 1660
    /// label map and a functor which converts the label map values to
1654 1661
    /// \c std::string.
1655 1662
    template <typename Map, typename Converter>
1656 1663
    GraphReader& useEdges(const Map& map,
1657 1664
                            const Converter& converter = Converter()) {
1658 1665
      checkConcept<concepts::ReadMap<Edge, typename Map::Value>, Map>();
1659 1666
      LEMON_ASSERT(!_use_edges, "Multiple usage of useEdges() member");
1660 1667
      _use_edges = true;
1661 1668
      for (EdgeIt a(_graph); a != INVALID; ++a) {
1662 1669
        _edge_index.insert(std::make_pair(converter(map[a]), a));
1663 1670
      }
1664 1671
      return *this;
1665 1672
    }
1666 1673

	
1667 1674
    /// \brief Skip the reading of node section
1668 1675
    ///
1669 1676
    /// Omit the reading of the node section. This implies that each node
1670 1677
    /// map reading rule will be abandoned, and the nodes of the graph
1671 1678
    /// will not be constructed, which usually cause that the edge set
1672 1679
    /// could not be read due to lack of node name
1673 1680
    /// could not be read due to lack of node name resolving.
1674 1681
    /// Therefore \c skipEdges() function should also be used, or
1675 1682
    /// \c useNodes() should be used to specify the label of the nodes.
1676 1683
    GraphReader& skipNodes() {
1677 1684
      LEMON_ASSERT(!_skip_nodes, "Skip nodes already set");
1678 1685
      _skip_nodes = true;
1679 1686
      return *this;
1680 1687
    }
1681 1688

	
1682 1689
    /// \brief Skip the reading of edge section
1683 1690
    ///
1684 1691
    /// Omit the reading of the edge section. This implies that each edge
1685 1692
    /// map reading rule will be abandoned, and the edges of the graph
1686 1693
    /// will not be constructed.
1687 1694
    GraphReader& skipEdges() {
1688 1695
      LEMON_ASSERT(!_skip_edges, "Skip edges already set");
1689 1696
      _skip_edges = true;
1690 1697
      return *this;
1691 1698
    }
1692 1699

	
1693 1700
    /// @}
1694 1701

	
1695 1702
  private:
1696 1703

	
1697 1704
    bool readLine() {
1698 1705
      std::string str;
1699 1706
      while(++line_num, std::getline(*_is, str)) {
1700 1707
        line.clear(); line.str(str);
1701 1708
        char c;
1702 1709
        if (line >> std::ws >> c && c != '#') {
1703 1710
          line.putback(c);
1704 1711
          return true;
1705 1712
        }
1706 1713
      }
1707 1714
      return false;
1708 1715
    }
1709 1716

	
1710 1717
    bool readSuccess() {
1711 1718
      return static_cast<bool>(*_is);
1712 1719
    }
1713 1720

	
1714 1721
    void skipSection() {
1715 1722
      char c;
1716 1723
      while (readSuccess() && line >> c && c != '@') {
1717 1724
        readLine();
1718 1725
      }
1719 1726
      if (readSuccess()) {
1720 1727
        line.putback(c);
1721 1728
      }
1722 1729
    }
1723 1730

	
1724 1731
    void readNodes() {
1725 1732

	
1726 1733
      std::vector<int> map_index(_node_maps.size());
1727 1734
      int map_num, label_index;
1728 1735

	
1729 1736
      char c;
1730 1737
      if (!readLine() || !(line >> c) || c == '@') {
1731 1738
        if (readSuccess() && line) line.putback(c);
1732 1739
        if (!_node_maps.empty())
1733 1740
          throw FormatError("Cannot find map names");
1734 1741
        return;
1735 1742
      }
1736 1743
      line.putback(c);
1737 1744

	
1738 1745
      {
1739 1746
        std::map<std::string, int> maps;
1740 1747

	
1741 1748
        std::string map;
1742 1749
        int index = 0;
1743 1750
        while (_reader_bits::readToken(line, map)) {
1744 1751
          if (maps.find(map) != maps.end()) {
1745 1752
            std::ostringstream msg;
1746 1753
            msg << "Multiple occurence of node map: " << map;
1747 1754
            throw FormatError(msg.str());
1748 1755
          }
1749 1756
          maps.insert(std::make_pair(map, index));
1750 1757
          ++index;
1751 1758
        }
1752 1759

	
1753 1760
        for (int i = 0; i < static_cast<int>(_node_maps.size()); ++i) {
1754 1761
          std::map<std::string, int>::iterator jt =
1755 1762
            maps.find(_node_maps[i].first);
1756 1763
          if (jt == maps.end()) {
1757 1764
            std::ostringstream msg;
1758 1765
            msg << "Map not found: " << _node_maps[i].first;
1759 1766
            throw FormatError(msg.str());
1760 1767
          }
1761 1768
          map_index[i] = jt->second;
1762 1769
        }
1763 1770

	
1764 1771
        {
1765 1772
          std::map<std::string, int>::iterator jt = maps.find("label");
1766 1773
          if (jt != maps.end()) {
1767 1774
            label_index = jt->second;
1768 1775
          } else {
1769 1776
            label_index = -1;
1770 1777
          }
1771 1778
        }
1772 1779
        map_num = maps.size();
1773 1780
      }
1774 1781

	
1775 1782
      while (readLine() && line >> c && c != '@') {
1776 1783
        line.putback(c);
1777 1784

	
1778 1785
        std::vector<std::string> tokens(map_num);
1779 1786
        for (int i = 0; i < map_num; ++i) {
1780 1787
          if (!_reader_bits::readToken(line, tokens[i])) {
1781 1788
            std::ostringstream msg;
1782 1789
            msg << "Column not found (" << i + 1 << ")";
1783 1790
            throw FormatError(msg.str());
1784 1791
          }
1785 1792
        }
1786 1793
        if (line >> std::ws >> c)
1787 1794
          throw FormatError("Extra character at the end of line");
1788 1795

	
1789 1796
        Node n;
1790 1797
        if (!_use_nodes) {
1791 1798
          n = _graph.addNode();
1792 1799
          if (label_index != -1)
1793 1800
            _node_index.insert(std::make_pair(tokens[label_index], n));
1794 1801
        } else {
1795 1802
          if (label_index == -1)
1796 1803
            throw FormatError("Label map not found");
1797 1804
          typename std::map<std::string, Node>::iterator it =
1798 1805
            _node_index.find(tokens[label_index]);
1799 1806
          if (it == _node_index.end()) {
1800 1807
            std::ostringstream msg;
1801 1808
            msg << "Node with label not found: " << tokens[label_index];
1802 1809
            throw FormatError(msg.str());
1803 1810
          }
1804 1811
          n = it->second;
1805 1812
        }
1806 1813

	
1807 1814
        for (int i = 0; i < static_cast<int>(_node_maps.size()); ++i) {
1808 1815
          _node_maps[i].second->set(n, tokens[map_index[i]]);
1809 1816
        }
1810 1817

	
1811 1818
      }
1812 1819
      if (readSuccess()) {
1813 1820
        line.putback(c);
1814 1821
      }
1815 1822
    }
1816 1823

	
1817 1824
    void readEdges() {
1818 1825

	
1819 1826
      std::vector<int> map_index(_edge_maps.size());
1820 1827
      int map_num, label_index;
1821 1828

	
1822 1829
      char c;
1823 1830
      if (!readLine() || !(line >> c) || c == '@') {
1824 1831
        if (readSuccess() && line) line.putback(c);
1825 1832
        if (!_edge_maps.empty())
1826 1833
          throw FormatError("Cannot find map names");
1827 1834
        return;
1828 1835
      }
1829 1836
      line.putback(c);
1830 1837

	
1831 1838
      {
1832 1839
        std::map<std::string, int> maps;
1833 1840

	
1834 1841
        std::string map;
1835 1842
        int index = 0;
1836 1843
        while (_reader_bits::readToken(line, map)) {
1844
          if(map == "-") {
1845
              if(index!=0)
1846
                throw FormatError("'-' is not allowed as a map name");
1847
              else if (line >> std::ws >> c)
1848
                throw FormatError("Extra character at the end of line");
1849
              else break;
1850
            }
1837 1851
          if (maps.find(map) != maps.end()) {
1838 1852
            std::ostringstream msg;
1839 1853
            msg << "Multiple occurence of edge map: " << map;
1840 1854
            throw FormatError(msg.str());
1841 1855
          }
1842 1856
          maps.insert(std::make_pair(map, index));
1843 1857
          ++index;
1844 1858
        }
1845 1859

	
1846 1860
        for (int i = 0; i < static_cast<int>(_edge_maps.size()); ++i) {
1847 1861
          std::map<std::string, int>::iterator jt =
1848 1862
            maps.find(_edge_maps[i].first);
1849 1863
          if (jt == maps.end()) {
1850 1864
            std::ostringstream msg;
1851 1865
            msg << "Map not found: " << _edge_maps[i].first;
1852 1866
            throw FormatError(msg.str());
1853 1867
          }
1854 1868
          map_index[i] = jt->second;
1855 1869
        }
1856 1870

	
1857 1871
        {
1858 1872
          std::map<std::string, int>::iterator jt = maps.find("label");
1859 1873
          if (jt != maps.end()) {
1860 1874
            label_index = jt->second;
1861 1875
          } else {
1862 1876
            label_index = -1;
1863 1877
          }
1864 1878
        }
1865 1879
        map_num = maps.size();
1866 1880
      }
1867 1881

	
1868 1882
      while (readLine() && line >> c && c != '@') {
1869 1883
        line.putback(c);
1870 1884

	
1871 1885
        std::string source_token;
1872 1886
        std::string target_token;
1873 1887

	
1874 1888
        if (!_reader_bits::readToken(line, source_token))
1875 1889
          throw FormatError("Node u not found");
1876 1890

	
1877 1891
        if (!_reader_bits::readToken(line, target_token))
1878 1892
          throw FormatError("Node v not found");
1879 1893

	
1880 1894
        std::vector<std::string> tokens(map_num);
1881 1895
        for (int i = 0; i < map_num; ++i) {
1882 1896
          if (!_reader_bits::readToken(line, tokens[i])) {
1883 1897
            std::ostringstream msg;
1884 1898
            msg << "Column not found (" << i + 1 << ")";
1885 1899
            throw FormatError(msg.str());
1886 1900
          }
1887 1901
        }
1888 1902
        if (line >> std::ws >> c)
1889 1903
          throw FormatError("Extra character at the end of line");
1890 1904

	
1891 1905
        Edge e;
1892 1906
        if (!_use_edges) {
1893 1907

	
1894 1908
          typename NodeIndex::iterator it;
1895 1909

	
1896 1910
          it = _node_index.find(source_token);
1897 1911
          if (it == _node_index.end()) {
1898 1912
            std::ostringstream msg;
1899 1913
            msg << "Item not found: " << source_token;
1900 1914
            throw FormatError(msg.str());
1901 1915
          }
1902 1916
          Node source = it->second;
1903 1917

	
1904 1918
          it = _node_index.find(target_token);
1905 1919
          if (it == _node_index.end()) {
1906 1920
            std::ostringstream msg;
1907 1921
            msg << "Item not found: " << target_token;
1908 1922
            throw FormatError(msg.str());
1909 1923
          }
1910 1924
          Node target = it->second;
1911 1925

	
1912 1926
          e = _graph.addEdge(source, target);
1913 1927
          if (label_index != -1)
1914 1928
            _edge_index.insert(std::make_pair(tokens[label_index], e));
1915 1929
        } else {
1916 1930
          if (label_index == -1)
1917 1931
            throw FormatError("Label map not found");
1918 1932
          typename std::map<std::string, Edge>::iterator it =
1919 1933
            _edge_index.find(tokens[label_index]);
1920 1934
          if (it == _edge_index.end()) {
1921 1935
            std::ostringstream msg;
1922 1936
            msg << "Edge with label not found: " << tokens[label_index];
1923 1937
            throw FormatError(msg.str());
1924 1938
          }
1925 1939
          e = it->second;
1926 1940
        }
1927 1941

	
1928 1942
        for (int i = 0; i < static_cast<int>(_edge_maps.size()); ++i) {
1929 1943
          _edge_maps[i].second->set(e, tokens[map_index[i]]);
1930 1944
        }
1931 1945

	
1932 1946
      }
1933 1947
      if (readSuccess()) {
1934 1948
        line.putback(c);
1935 1949
      }
1936 1950
    }
1937 1951

	
1938 1952
    void readAttributes() {
1939 1953

	
1940 1954
      std::set<std::string> read_attr;
1941 1955

	
1942 1956
      char c;
1943 1957
      while (readLine() && line >> c && c != '@') {
1944 1958
        line.putback(c);
1945 1959

	
1946 1960
        std::string attr, token;
1947 1961
        if (!_reader_bits::readToken(line, attr))
1948 1962
          throw FormatError("Attribute name not found");
1949 1963
        if (!_reader_bits::readToken(line, token))
1950 1964
          throw FormatError("Attribute value not found");
1951 1965
        if (line >> c)
1952 1966
          throw FormatError("Extra character at the end of line");
1953 1967

	
1954 1968
        {
1955 1969
          std::set<std::string>::iterator it = read_attr.find(attr);
1956 1970
          if (it != read_attr.end()) {
1957 1971
            std::ostringstream msg;
1958 1972
            msg << "Multiple occurence of attribute: " << attr;
1959 1973
            throw FormatError(msg.str());
1960 1974
          }
1961 1975
          read_attr.insert(attr);
1962 1976
        }
1963 1977

	
1964 1978
        {
1965 1979
          typename Attributes::iterator it = _attributes.lower_bound(attr);
1966 1980
          while (it != _attributes.end() && it->first == attr) {
1967 1981
            it->second->set(token);
1968 1982
            ++it;
1969 1983
          }
1970 1984
        }
1971 1985

	
1972 1986
      }
1973 1987
      if (readSuccess()) {
1974 1988
        line.putback(c);
1975 1989
      }
1976 1990
      for (typename Attributes::iterator it = _attributes.begin();
1977 1991
           it != _attributes.end(); ++it) {
1978 1992
        if (read_attr.find(it->first) == read_attr.end()) {
1979 1993
          std::ostringstream msg;
1980 1994
          msg << "Attribute not found: " << it->first;
1981 1995
          throw FormatError(msg.str());
1982 1996
        }
1983 1997
      }
1984 1998
    }
1985 1999

	
1986 2000
  public:
1987 2001

	
1988 2002
    /// \name Execution of the Reader
1989 2003
    /// @{
1990 2004

	
1991 2005
    /// \brief Start the batch processing
1992 2006
    ///
1993 2007
    /// This function starts the batch processing
1994 2008
    void run() {
1995 2009

	
1996 2010
      LEMON_ASSERT(_is != 0, "This reader assigned to an other reader");
1997 2011

	
1998 2012
      bool nodes_done = _skip_nodes;
1999 2013
      bool edges_done = _skip_edges;
2000 2014
      bool attributes_done = false;
2001 2015

	
2002 2016
      line_num = 0;
2003 2017
      readLine();
2004 2018
      skipSection();
2005 2019

	
2006 2020
      while (readSuccess()) {
2007 2021
        try {
2008 2022
          char c;
2009 2023
          std::string section, caption;
2010 2024
          line >> c;
2011 2025
          _reader_bits::readToken(line, section);
2012 2026
          _reader_bits::readToken(line, caption);
2013 2027

	
2014 2028
          if (line >> c)
2015 2029
            throw FormatError("Extra character at the end of line");
2016 2030

	
2017 2031
          if (section == "nodes" && !nodes_done) {
2018 2032
            if (_nodes_caption.empty() || _nodes_caption == caption) {
2019 2033
              readNodes();
2020 2034
              nodes_done = true;
2021 2035
            }
2022 2036
          } else if ((section == "edges" || section == "arcs") &&
2023 2037
                     !edges_done) {
2024 2038
            if (_edges_caption.empty() || _edges_caption == caption) {
2025 2039
              readEdges();
2026 2040
              edges_done = true;
2027 2041
            }
2028 2042
          } else if (section == "attributes" && !attributes_done) {
2029 2043
            if (_attributes_caption.empty() || _attributes_caption == caption) {
2030 2044
              readAttributes();
2031 2045
              attributes_done = true;
2032 2046
            }
2033 2047
          } else {
2034 2048
            readLine();
2035 2049
            skipSection();
2036 2050
          }
2037 2051
        } catch (FormatError& error) {
2038 2052
          error.line(line_num);
2039 2053
          error.file(_filename);
2040 2054
          throw;
2041 2055
        }
2042 2056
      }
2043 2057

	
2044 2058
      if (!nodes_done) {
2045 2059
        throw FormatError("Section @nodes not found");
2046 2060
      }
2047 2061

	
2048 2062
      if (!edges_done) {
2049 2063
        throw FormatError("Section @edges not found");
2050 2064
      }
2051 2065

	
2052 2066
      if (!attributes_done && !_attributes.empty()) {
2053 2067
        throw FormatError("Section @attributes not found");
2054 2068
      }
2055 2069

	
2056 2070
    }
2057 2071

	
2058 2072
    /// @}
2059 2073

	
2060 2074
  };
2061 2075

	
2062 2076
  /// \ingroup lemon_io
2063 2077
  ///
2064 2078
  /// \brief Return a \ref GraphReader class
2065 2079
  ///
2066 2080
  /// This function just returns a \ref GraphReader class.
2067 2081
  ///
2068 2082
  /// With this function a graph can be read from an
2069 2083
  /// \ref lgf-format "LGF" file or input stream with several maps and
2070 2084
  /// attributes. For example, there is weighted matching problem on a
2071 2085
  /// graph, i.e. a graph with a \e weight map on the edges. This
2072 2086
  /// graph can be read with the following code:
2073 2087
  ///
2074 2088
  ///\code
2075 2089
  ///ListGraph graph;
2076 2090
  ///ListGraph::EdgeMap<int> weight(graph);
2077 2091
  ///graphReader(graph, std::cin).
2078 2092
  ///  edgeMap("weight", weight).
2079 2093
  ///  run();
2080 2094
  ///\endcode
2081 2095
  ///
2082 2096
  /// For a complete documentation, please see the \ref GraphReader
2083 2097
  /// class documentation.
2084 2098
  /// \warning Don't forget to put the \ref GraphReader::run() "run()"
2085 2099
  /// to the end of the parameter list.
2086 2100
  /// \relates GraphReader
2087 2101
  /// \sa graphReader(TGR& graph, const std::string& fn)
2088 2102
  /// \sa graphReader(TGR& graph, const char* fn)
2089 2103
  template <typename TGR>
2090 2104
  GraphReader<TGR> graphReader(TGR& graph, std::istream& is) {
2091 2105
    GraphReader<TGR> tmp(graph, is);
2092 2106
    return tmp;
2093 2107
  }
2094 2108

	
2095 2109
  /// \brief Return a \ref GraphReader class
2096 2110
  ///
2097 2111
  /// This function just returns a \ref GraphReader class.
2098 2112
  /// \relates GraphReader
2099 2113
  /// \sa graphReader(TGR& graph, std::istream& is)
2100 2114
  template <typename TGR>
2101 2115
  GraphReader<TGR> graphReader(TGR& graph, const std::string& fn) {
2102 2116
    GraphReader<TGR> tmp(graph, fn);
2103 2117
    return tmp;
2104 2118
  }
2105 2119

	
2106 2120
  /// \brief Return a \ref GraphReader class
2107 2121
  ///
2108 2122
  /// This function just returns a \ref GraphReader class.
2109 2123
  /// \relates GraphReader
2110 2124
  /// \sa graphReader(TGR& graph, std::istream& is)
2111 2125
  template <typename TGR>
2112 2126
  GraphReader<TGR> graphReader(TGR& graph, const char* fn) {
2113 2127
    GraphReader<TGR> tmp(graph, fn);
2114 2128
    return tmp;
2115 2129
  }
2116 2130

	
2117 2131
  class SectionReader;
2118 2132

	
2119 2133
  SectionReader sectionReader(std::istream& is);
2120 2134
  SectionReader sectionReader(const std::string& fn);
2121 2135
  SectionReader sectionReader(const char* fn);
2122 2136

	
2123 2137
  /// \ingroup lemon_io
2124 2138
  ///
2125 2139
  /// \brief Section reader class
2126 2140
  ///
2127 2141
  /// In the \ref lgf-format "LGF" file extra sections can be placed,
2128 2142
  /// which contain any data in arbitrary format. Such sections can be
2129 2143
  /// read with this class. A reading rule can be added to the class
2130 2144
  /// with two different functions. With the \c sectionLines() function a
2131 2145
  /// functor can process the section line-by-line, while with the \c
2132 2146
  /// sectionStream() member the section can be read from an input
2133 2147
  /// stream.
2134 2148
  class SectionReader {
2135 2149
  private:
2136 2150

	
2137 2151
    std::istream* _is;
2138 2152
    bool local_is;
2139 2153
    std::string _filename;
2140 2154

	
2141 2155
    typedef std::map<std::string, _reader_bits::Section*> Sections;
2142 2156
    Sections _sections;
2143 2157

	
2144 2158
    int line_num;
2145 2159
    std::istringstream line;
2146 2160

	
2147 2161
  public:
2148 2162

	
2149 2163
    /// \brief Constructor
2150 2164
    ///
2151 2165
    /// Construct a section reader, which reads from the given input
2152 2166
    /// stream.
2153 2167
    SectionReader(std::istream& is)
2154 2168
      : _is(&is), local_is(false) {}
2155 2169

	
2156 2170
    /// \brief Constructor
2157 2171
    ///
2158 2172
    /// Construct a section reader, which reads from the given file.
2159 2173
    SectionReader(const std::string& fn)
2160 2174
      : _is(new std::ifstream(fn.c_str())), local_is(true),
2161 2175
        _filename(fn) {
2162 2176
      if (!(*_is)) {
2163 2177
        delete _is;
2164 2178
        throw IoError("Cannot open file", fn);
2165 2179
      }
2166 2180
    }
2167 2181

	
2168 2182
    /// \brief Constructor
2169 2183
    ///
2170 2184
    /// Construct a section reader, which reads from the given file.
2171 2185
    SectionReader(const char* fn)
2172 2186
      : _is(new std::ifstream(fn)), local_is(true),
2173 2187
        _filename(fn) {
2174 2188
      if (!(*_is)) {
2175 2189
        delete _is;
2176 2190
        throw IoError("Cannot open file", fn);
2177 2191
      }
2178 2192
    }
2179 2193

	
2180 2194
    /// \brief Destructor
2181 2195
    ~SectionReader() {
2182 2196
      for (Sections::iterator it = _sections.begin();
2183 2197
           it != _sections.end(); ++it) {
2184 2198
        delete it->second;
2185 2199
      }
2186 2200

	
2187 2201
      if (local_is) {
2188 2202
        delete _is;
2189 2203
      }
2190 2204

	
2191 2205
    }
2192 2206

	
2193 2207
  private:
2194 2208

	
2195 2209
    friend SectionReader sectionReader(std::istream& is);
2196 2210
    friend SectionReader sectionReader(const std::string& fn);
2197 2211
    friend SectionReader sectionReader(const char* fn);
2198 2212

	
2199 2213
    SectionReader(SectionReader& other)
2200 2214
      : _is(other._is), local_is(other.local_is) {
2201 2215

	
2202 2216
      other._is = 0;
2203 2217
      other.local_is = false;
2204 2218

	
2205 2219
      _sections.swap(other._sections);
2206 2220
    }
2207 2221

	
2208 2222
    SectionReader& operator=(const SectionReader&);
2209 2223

	
2210 2224
  public:
2211 2225

	
2212 2226
    /// \name Section Readers
2213 2227
    /// @{
2214 2228

	
2215 2229
    /// \brief Add a section processor with line oriented reading
2216 2230
    ///
2217 2231
    /// The first parameter is the type descriptor of the section, the
2218 2232
    /// second is a functor, which takes just one \c std::string
2219 2233
    /// parameter. At the reading process, each line of the section
2220 2234
    /// will be given to the functor object. However, the empty lines
2221 2235
    /// and the comment lines are filtered out, and the leading
2222 2236
    /// whitespaces are trimmed from each processed string.
2223 2237
    ///
2224 2238
    /// For example, let's see a section, which contain several
2225 2239
    /// integers, which should be inserted into a vector.
2226 2240
    ///\code
2227 2241
    ///  @numbers
2228 2242
    ///  12 45 23
2229 2243
    ///  4
2230 2244
    ///  23 6
2231 2245
    ///\endcode
2232 2246
    ///
2233 2247
    /// The functor is implemented as a struct:
2234 2248
    ///\code
2235 2249
    ///  struct NumberSection {
2236 2250
    ///    std::vector<int>& _data;
2237 2251
    ///    NumberSection(std::vector<int>& data) : _data(data) {}
2238 2252
    ///    void operator()(const std::string& line) {
2239 2253
    ///      std::istringstream ls(line);
2240 2254
    ///      int value;
2241 2255
    ///      while (ls >> value) _data.push_back(value);
2242 2256
    ///    }
2243 2257
    ///  };
2244 2258
    ///
2245 2259
    ///  // ...
2246 2260
    ///
2247 2261
    ///  reader.sectionLines("numbers", NumberSection(vec));
2248 2262
    ///\endcode
2249 2263
    template <typename Functor>
2250 2264
    SectionReader& sectionLines(const std::string& type, Functor functor) {
2251 2265
      LEMON_ASSERT(!type.empty(), "Type is empty.");
2252 2266
      LEMON_ASSERT(_sections.find(type) == _sections.end(),
2253 2267
                   "Multiple reading of section.");
2254 2268
      _sections.insert(std::make_pair(type,
2255 2269
        new _reader_bits::LineSection<Functor>(functor)));
2256 2270
      return *this;
2257 2271
    }
2258 2272

	
2259 2273

	
2260 2274
    /// \brief Add a section processor with stream oriented reading
2261 2275
    ///
2262 2276
    /// The first parameter is the type of the section, the second is
2263 2277
    /// a functor, which takes an \c std::istream& and an \c int&
2264 2278
    /// parameter, the latter regard to the line number of stream. The
2265 2279
    /// functor can read the input while the section go on, and the
2266 2280
    /// line number should be modified accordingly.
2267 2281
    template <typename Functor>
2268 2282
    SectionReader& sectionStream(const std::string& type, Functor functor) {
2269 2283
      LEMON_ASSERT(!type.empty(), "Type is empty.");
2270 2284
      LEMON_ASSERT(_sections.find(type) == _sections.end(),
2271 2285
                   "Multiple reading of section.");
2272 2286
      _sections.insert(std::make_pair(type,
2273 2287
         new _reader_bits::StreamSection<Functor>(functor)));
2274 2288
      return *this;
2275 2289
    }
2276 2290

	
2277 2291
    /// @}
2278 2292

	
2279 2293
  private:
2280 2294

	
2281 2295
    bool readLine() {
2282 2296
      std::string str;
2283 2297
      while(++line_num, std::getline(*_is, str)) {
2284 2298
        line.clear(); line.str(str);
2285 2299
        char c;
2286 2300
        if (line >> std::ws >> c && c != '#') {
2287 2301
          line.putback(c);
2288 2302
          return true;
2289 2303
        }
2290 2304
      }
2291 2305
      return false;
2292 2306
    }
2293 2307

	
2294 2308
    bool readSuccess() {
2295 2309
      return static_cast<bool>(*_is);
2296 2310
    }
2297 2311

	
2298 2312
    void skipSection() {
2299 2313
      char c;
2300 2314
      while (readSuccess() && line >> c && c != '@') {
2301 2315
        readLine();
2302 2316
      }
2303 2317
      if (readSuccess()) {
2304 2318
        line.putback(c);
2305 2319
      }
2306 2320
    }
2307 2321

	
2308 2322
  public:
2309 2323

	
2310 2324

	
2311 2325
    /// \name Execution of the Reader
2312 2326
    /// @{
2313 2327

	
2314 2328
    /// \brief Start the batch processing
2315 2329
    ///
2316 2330
    /// This function starts the batch processing.
2317 2331
    void run() {
2318 2332

	
2319 2333
      LEMON_ASSERT(_is != 0, "This reader assigned to an other reader");
2320 2334

	
2321 2335
      std::set<std::string> extra_sections;
2322 2336

	
2323 2337
      line_num = 0;
2324 2338
      readLine();
2325 2339
      skipSection();
2326 2340

	
2327 2341
      while (readSuccess()) {
2328 2342
        try {
2329 2343
          char c;
2330 2344
          std::string section, caption;
2331 2345
          line >> c;
2332 2346
          _reader_bits::readToken(line, section);
2333 2347
          _reader_bits::readToken(line, caption);
2334 2348

	
2335 2349
          if (line >> c)
2336 2350
            throw FormatError("Extra character at the end of line");
2337 2351

	
2338 2352
          if (extra_sections.find(section) != extra_sections.end()) {
2339 2353
            std::ostringstream msg;
2340 2354
            msg << "Multiple occurence of section: " << section;
2341 2355
            throw FormatError(msg.str());
2342 2356
          }
2343 2357
          Sections::iterator it = _sections.find(section);
2344 2358
          if (it != _sections.end()) {
2345 2359
            extra_sections.insert(section);
2346 2360
            it->second->process(*_is, line_num);
2347 2361
          }
2348 2362
          readLine();
2349 2363
          skipSection();
2350 2364
        } catch (FormatError& error) {
2351 2365
          error.line(line_num);
2352 2366
          error.file(_filename);
2353 2367
          throw;
2354 2368
        }
2355 2369
      }
2356 2370
      for (Sections::iterator it = _sections.begin();
2357 2371
           it != _sections.end(); ++it) {
2358 2372
        if (extra_sections.find(it->first) == extra_sections.end()) {
2359 2373
          std::ostringstream os;
2360 2374
          os << "Cannot find section: " << it->first;
2361 2375
          throw FormatError(os.str());
2362 2376
        }
2363 2377
      }
2364 2378
    }
2365 2379

	
2366 2380
    /// @}
2367 2381

	
2368 2382
  };
2369 2383

	
2370 2384
  /// \ingroup lemon_io
2371 2385
  ///
2372 2386
  /// \brief Return a \ref SectionReader class
2373 2387
  ///
2374 2388
  /// This function just returns a \ref SectionReader class.
2375 2389
  ///
2376 2390
  /// Please see SectionReader documentation about the custom section
2377 2391
  /// input.
2378 2392
  ///
2379 2393
  /// \relates SectionReader
2380 2394
  /// \sa sectionReader(const std::string& fn)
2381 2395
  /// \sa sectionReader(const char *fn)
2382 2396
  inline SectionReader sectionReader(std::istream& is) {
2383 2397
    SectionReader tmp(is);
2384 2398
    return tmp;
2385 2399
  }
2386 2400

	
2387 2401
  /// \brief Return a \ref SectionReader class
2388 2402
  ///
2389 2403
  /// This function just returns a \ref SectionReader class.
2390 2404
  /// \relates SectionReader
2391 2405
  /// \sa sectionReader(std::istream& is)
2392 2406
  inline SectionReader sectionReader(const std::string& fn) {
2393 2407
    SectionReader tmp(fn);
2394 2408
    return tmp;
2395 2409
  }
2396 2410

	
2397 2411
  /// \brief Return a \ref SectionReader class
2398 2412
  ///
2399 2413
  /// This function just returns a \ref SectionReader class.
2400 2414
  /// \relates SectionReader
2401 2415
  /// \sa sectionReader(std::istream& is)
2402 2416
  inline SectionReader sectionReader(const char* fn) {
2403 2417
    SectionReader tmp(fn);
2404 2418
    return tmp;
2405 2419
  }
2406 2420

	
2407 2421
  /// \ingroup lemon_io
2408 2422
  ///
2409 2423
  /// \brief Reader for the contents of the \ref lgf-format "LGF" file
2410 2424
  ///
2411 2425
  /// This class can be used to read the sections, the map names and
2412 2426
  /// the attributes from a file. Usually, the LEMON programs know
2413 2427
  /// that, which type of graph, which maps and which attributes
2414 2428
  /// should be read from a file, but in general tools (like glemon)
2415 2429
  /// the contents of an LGF file should be guessed somehow. This class
2416 2430
  /// reads the graph and stores the appropriate information for
2417 2431
  /// reading the graph.
2418 2432
  ///
2419 2433
  ///\code
2420 2434
  /// LgfContents contents("graph.lgf");
2421 2435
  /// contents.run();
2422 2436
  ///
2423 2437
  /// // Does it contain any node section and arc section?
2424 2438
  /// if (contents.nodeSectionNum() == 0 || contents.arcSectionNum()) {
2425 2439
  ///   std::cerr << "Failure, cannot find graph." << std::endl;
2426 2440
  ///   return -1;
2427 2441
  /// }
2428 2442
  /// std::cout << "The name of the default node section: "
2429 2443
  ///           << contents.nodeSection(0) << std::endl;
2430 2444
  /// std::cout << "The number of the arc maps: "
2431 2445
  ///           << contents.arcMaps(0).size() << std::endl;
2432 2446
  /// std::cout << "The name of second arc map: "
2433 2447
  ///           << contents.arcMaps(0)[1] << std::endl;
2434 2448
  ///\endcode
2435 2449
  class LgfContents {
2436 2450
  private:
2437 2451

	
2438 2452
    std::istream* _is;
2439 2453
    bool local_is;
2440 2454

	
2441 2455
    std::vector<std::string> _node_sections;
2442 2456
    std::vector<std::string> _edge_sections;
2443 2457
    std::vector<std::string> _attribute_sections;
2444 2458
    std::vector<std::string> _extra_sections;
2445 2459

	
2446 2460
    std::vector<bool> _arc_sections;
2447 2461

	
2448 2462
    std::vector<std::vector<std::string> > _node_maps;
2449 2463
    std::vector<std::vector<std::string> > _edge_maps;
2450 2464

	
2451 2465
    std::vector<std::vector<std::string> > _attributes;
2452 2466

	
2453 2467

	
2454 2468
    int line_num;
2455 2469
    std::istringstream line;
2456 2470

	
2457 2471
  public:
2458 2472

	
2459 2473
    /// \brief Constructor
2460 2474
    ///
2461 2475
    /// Construct an \e LGF contents reader, which reads from the given
2462 2476
    /// input stream.
2463 2477
    LgfContents(std::istream& is)
2464 2478
      : _is(&is), local_is(false) {}
2465 2479

	
2466 2480
    /// \brief Constructor
2467 2481
    ///
2468 2482
    /// Construct an \e LGF contents reader, which reads from the given
2469 2483
    /// file.
2470 2484
    LgfContents(const std::string& fn)
2471 2485
      : _is(new std::ifstream(fn.c_str())), local_is(true) {
2472 2486
      if (!(*_is)) {
2473 2487
        delete _is;
2474 2488
        throw IoError("Cannot open file", fn);
2475 2489
      }
2476 2490
    }
2477 2491

	
2478 2492
    /// \brief Constructor
2479 2493
    ///
2480 2494
    /// Construct an \e LGF contents reader, which reads from the given
2481 2495
    /// file.
2482 2496
    LgfContents(const char* fn)
2483 2497
      : _is(new std::ifstream(fn)), local_is(true) {
2484 2498
      if (!(*_is)) {
2485 2499
        delete _is;
2486 2500
        throw IoError("Cannot open file", fn);
2487 2501
      }
2488 2502
    }
2489 2503

	
2490 2504
    /// \brief Destructor
2491 2505
    ~LgfContents() {
2492 2506
      if (local_is) delete _is;
2493 2507
    }
2494 2508

	
2495 2509
  private:
2496 2510

	
2497 2511
    LgfContents(const LgfContents&);
2498 2512
    LgfContents& operator=(const LgfContents&);
2499 2513

	
2500 2514
  public:
2501 2515

	
2502 2516

	
2503 2517
    /// \name Node Sections
2504 2518
    /// @{
2505 2519

	
2506 2520
    /// \brief Gives back the number of node sections in the file.
2507 2521
    ///
2508 2522
    /// Gives back the number of node sections in the file.
2509 2523
    int nodeSectionNum() const {
2510 2524
      return _node_sections.size();
2511 2525
    }
2512 2526

	
2513 2527
    /// \brief Returns the node section name at the given position.
2514 2528
    ///
2515 2529
    /// Returns the node section name at the given position.
2516 2530
    const std::string& nodeSection(int i) const {
2517 2531
      return _node_sections[i];
2518 2532
    }
2519 2533

	
2520 2534
    /// \brief Gives back the node maps for the given section.
2521 2535
    ///
2522 2536
    /// Gives back the node maps for the given section.
2523 2537
    const std::vector<std::string>& nodeMapNames(int i) const {
2524 2538
      return _node_maps[i];
2525 2539
    }
2526 2540

	
2527 2541
    /// @}
2528 2542

	
2529 2543
    /// \name Arc/Edge Sections
2530 2544
    /// @{
2531 2545

	
2532 2546
    /// \brief Gives back the number of arc/edge sections in the file.
2533 2547
    ///
2534 2548
    /// Gives back the number of arc/edge sections in the file.
2535 2549
    /// \note It is synonym of \c edgeSectionNum().
2536 2550
    int arcSectionNum() const {
2537 2551
      return _edge_sections.size();
2538 2552
    }
2539 2553

	
2540 2554
    /// \brief Returns the arc/edge section name at the given position.
2541 2555
    ///
2542 2556
    /// Returns the arc/edge section name at the given position.
2543 2557
    /// \note It is synonym of \c edgeSection().
2544 2558
    const std::string& arcSection(int i) const {
2545 2559
      return _edge_sections[i];
2546 2560
    }
2547 2561

	
2548 2562
    /// \brief Gives back the arc/edge maps for the given section.
2549 2563
    ///
2550 2564
    /// Gives back the arc/edge maps for the given section.
2551 2565
    /// \note It is synonym of \c edgeMapNames().
2552 2566
    const std::vector<std::string>& arcMapNames(int i) const {
2553 2567
      return _edge_maps[i];
2554 2568
    }
2555 2569

	
2556 2570
    /// @}
2557 2571

	
2558 2572
    /// \name Synonyms
2559 2573
    /// @{
2560 2574

	
2561 2575
    /// \brief Gives back the number of arc/edge sections in the file.
2562 2576
    ///
2563 2577
    /// Gives back the number of arc/edge sections in the file.
2564 2578
    /// \note It is synonym of \c arcSectionNum().
2565 2579
    int edgeSectionNum() const {
2566 2580
      return _edge_sections.size();
2567 2581
    }
2568 2582

	
2569 2583
    /// \brief Returns the section name at the given position.
2570 2584
    ///
2571 2585
    /// Returns the section name at the given position.
2572 2586
    /// \note It is synonym of \c arcSection().
2573 2587
    const std::string& edgeSection(int i) const {
2574 2588
      return _edge_sections[i];
2575 2589
    }
2576 2590

	
2577 2591
    /// \brief Gives back the edge maps for the given section.
2578 2592
    ///
2579 2593
    /// Gives back the edge maps for the given section.
2580 2594
    /// \note It is synonym of \c arcMapNames().
2581 2595
    const std::vector<std::string>& edgeMapNames(int i) const {
2582 2596
      return _edge_maps[i];
2583 2597
    }
2584 2598

	
2585 2599
    /// @}
2586 2600

	
2587 2601
    /// \name Attribute Sections
2588 2602
    /// @{
2589 2603

	
2590 2604
    /// \brief Gives back the number of attribute sections in the file.
2591 2605
    ///
2592 2606
    /// Gives back the number of attribute sections in the file.
2593 2607
    int attributeSectionNum() const {
2594 2608
      return _attribute_sections.size();
2595 2609
    }
2596 2610

	
2597 2611
    /// \brief Returns the attribute section name at the given position.
2598 2612
    ///
2599 2613
    /// Returns the attribute section name at the given position.
2600 2614
    const std::string& attributeSectionNames(int i) const {
2601 2615
      return _attribute_sections[i];
2602 2616
    }
2603 2617

	
2604 2618
    /// \brief Gives back the attributes for the given section.
2605 2619
    ///
2606 2620
    /// Gives back the attributes for the given section.
2607 2621
    const std::vector<std::string>& attributes(int i) const {
2608 2622
      return _attributes[i];
2609 2623
    }
2610 2624

	
2611 2625
    /// @}
2612 2626

	
2613 2627
    /// \name Extra Sections
2614 2628
    /// @{
2615 2629

	
2616 2630
    /// \brief Gives back the number of extra sections in the file.
2617 2631
    ///
2618 2632
    /// Gives back the number of extra sections in the file.
2619 2633
    int extraSectionNum() const {
2620 2634
      return _extra_sections.size();
2621 2635
    }
2622 2636

	
2623 2637
    /// \brief Returns the extra section type at the given position.
2624 2638
    ///
2625 2639
    /// Returns the section type at the given position.
2626 2640
    const std::string& extraSection(int i) const {
2627 2641
      return _extra_sections[i];
2628 2642
    }
2629 2643

	
2630 2644
    /// @}
2631 2645

	
2632 2646
  private:
2633 2647

	
2634 2648
    bool readLine() {
2635 2649
      std::string str;
2636 2650
      while(++line_num, std::getline(*_is, str)) {
2637 2651
        line.clear(); line.str(str);
2638 2652
        char c;
2639 2653
        if (line >> std::ws >> c && c != '#') {
2640 2654
          line.putback(c);
2641 2655
          return true;
2642 2656
        }
2643 2657
      }
2644 2658
      return false;
2645 2659
    }
2646 2660

	
2647 2661
    bool readSuccess() {
2648 2662
      return static_cast<bool>(*_is);
2649 2663
    }
2650 2664

	
2651 2665
    void skipSection() {
2652 2666
      char c;
2653 2667
      while (readSuccess() && line >> c && c != '@') {
2654 2668
        readLine();
2655 2669
      }
2656 2670
      if (readSuccess()) {
2657 2671
        line.putback(c);
2658 2672
      }
2659 2673
    }
2660 2674

	
2661 2675
    void readMaps(std::vector<std::string>& maps) {
2662 2676
      char c;
2663 2677
      if (!readLine() || !(line >> c) || c == '@') {
2664 2678
        if (readSuccess() && line) line.putback(c);
2665 2679
        return;
2666 2680
      }
2667 2681
      line.putback(c);
2668 2682
      std::string map;
2669 2683
      while (_reader_bits::readToken(line, map)) {
2670 2684
        maps.push_back(map);
2671 2685
      }
2672 2686
    }
2673 2687

	
2674 2688
    void readAttributes(std::vector<std::string>& attrs) {
2675 2689
      readLine();
2676 2690
      char c;
2677 2691
      while (readSuccess() && line >> c && c != '@') {
2678 2692
        line.putback(c);
2679 2693
        std::string attr;
2680 2694
        _reader_bits::readToken(line, attr);
2681 2695
        attrs.push_back(attr);
2682 2696
        readLine();
2683 2697
      }
2684 2698
      line.putback(c);
2685 2699
    }
2686 2700

	
2687 2701
  public:
2688 2702

	
2689 2703
    /// \name Execution of the Contents Reader
2690 2704
    /// @{
2691 2705

	
2692 2706
    /// \brief Starts the reading
2693 2707
    ///
2694 2708
    /// This function starts the reading.
2695 2709
    void run() {
2696 2710

	
2697 2711
      readLine();
2698 2712
      skipSection();
2699 2713

	
2700 2714
      while (readSuccess()) {
2701 2715

	
2702 2716
        char c;
2703 2717
        line >> c;
2704 2718

	
2705 2719
        std::string section, caption;
2706 2720
        _reader_bits::readToken(line, section);
2707 2721
        _reader_bits::readToken(line, caption);
2708 2722

	
2709 2723
        if (section == "nodes") {
2710 2724
          _node_sections.push_back(caption);
2711 2725
          _node_maps.push_back(std::vector<std::string>());
2712 2726
          readMaps(_node_maps.back());
2713 2727
          readLine(); skipSection();
2714 2728
        } else if (section == "arcs" || section == "edges") {
2715 2729
          _edge_sections.push_back(caption);
2716 2730
          _arc_sections.push_back(section == "arcs");
2717 2731
          _edge_maps.push_back(std::vector<std::string>());
2718 2732
          readMaps(_edge_maps.back());
2719 2733
          readLine(); skipSection();
2720 2734
        } else if (section == "attributes") {
2721 2735
          _attribute_sections.push_back(caption);
2722 2736
          _attributes.push_back(std::vector<std::string>());
2723 2737
          readAttributes(_attributes.back());
2724 2738
        } else {
2725 2739
          _extra_sections.push_back(section);
2726 2740
          readLine(); skipSection();
2727 2741
        }
2728 2742
      }
2729 2743
    }
2730 2744

	
2731 2745
    /// @}
2732 2746

	
2733 2747
  };
2734 2748
}
2735 2749

	
2736 2750
#endif
Show white space 3072 line context
1 1
INCLUDE_DIRECTORIES(
2 2
  ${PROJECT_SOURCE_DIR}
3 3
  ${PROJECT_BINARY_DIR}
4 4
)
5 5

	
6 6
LINK_DIRECTORIES(
7 7
  ${PROJECT_BINARY_DIR}/lemon
8 8
)
9 9

	
10 10
SET(TEST_WITH_VALGRIND "NO" CACHE STRING
11 11
  "Run the test with valgrind (YES/NO).")
12 12
SET(VALGRIND_FLAGS "" CACHE STRING "Valgrind flags used by the tests.")
13 13

	
14 14
SET(TESTS
15 15
  adaptors_test
16 16
  bellman_ford_test
17 17
  bfs_test
18 18
  circulation_test
19 19
  connectivity_test
20 20
  counter_test
21 21
  dfs_test
22 22
  digraph_test
23 23
  dijkstra_test
24 24
  dim_test
25 25
  edge_set_test
26 26
  error_test
27 27
  euler_test
28 28
  fractional_matching_test
29 29
  gomory_hu_test
30 30
  graph_copy_test
31 31
  graph_test
32 32
  graph_utils_test
33 33
  hao_orlin_test
34 34
  heap_test
35 35
  kruskal_test
36
  lgf_test
36 37
  maps_test
37 38
  matching_test
38 39
  min_cost_arborescence_test
39 40
  min_cost_flow_test
40 41
  min_mean_cycle_test
41 42
  path_test
42 43
  planarity_test
43 44
  preflow_test
44 45
  radix_sort_test
45 46
  random_test
46 47
  suurballe_test
47 48
  time_measure_test
48 49
  unionfind_test
49 50
)
50 51

	
51 52
IF(LEMON_HAVE_LP)
52 53
  IF(${CMAKE_BUILD_TYPE} STREQUAL "Maintainer")
53 54
    ADD_EXECUTABLE(lp_test lp_test.cc)
54 55
  ELSE()
55 56
    ADD_EXECUTABLE(lp_test EXCLUDE_FROM_ALL lp_test.cc)
56 57
  ENDIF()
57 58

	
58 59
  SET(LP_TEST_LIBS lemon)
59 60

	
60 61
  IF(LEMON_HAVE_GLPK)
61 62
    SET(LP_TEST_LIBS ${LP_TEST_LIBS} ${GLPK_LIBRARIES})
62 63
  ENDIF()
63 64
  IF(LEMON_HAVE_CPLEX)
64 65
    SET(LP_TEST_LIBS ${LP_TEST_LIBS} ${CPLEX_LIBRARIES})
65 66
  ENDIF()
66 67
  IF(LEMON_HAVE_CLP)
67 68
    SET(LP_TEST_LIBS ${LP_TEST_LIBS} ${COIN_CLP_LIBRARIES})
68 69
  ENDIF()
69 70

	
70 71
  TARGET_LINK_LIBRARIES(lp_test ${LP_TEST_LIBS})
71 72
  ADD_TEST(lp_test lp_test)
72 73
  ADD_DEPENDENCIES(check lp_test)
73 74

	
74 75
  IF(WIN32 AND LEMON_HAVE_GLPK)
75 76
    GET_TARGET_PROPERTY(TARGET_LOC lp_test LOCATION)
76 77
    GET_FILENAME_COMPONENT(TARGET_PATH ${TARGET_LOC} PATH)
77 78
    ADD_CUSTOM_COMMAND(TARGET lp_test POST_BUILD
78 79
      COMMAND ${CMAKE_COMMAND} -E copy ${GLPK_BIN_DIR}/glpk.dll ${TARGET_PATH}
79 80
      COMMAND ${CMAKE_COMMAND} -E copy ${GLPK_BIN_DIR}/libltdl3.dll ${TARGET_PATH}
80 81
      COMMAND ${CMAKE_COMMAND} -E copy ${GLPK_BIN_DIR}/zlib1.dll ${TARGET_PATH}
81 82
    )
82 83
  ENDIF()
83 84

	
84 85
  IF(WIN32 AND LEMON_HAVE_CPLEX)
85 86
    GET_TARGET_PROPERTY(TARGET_LOC lp_test LOCATION)
86 87
    GET_FILENAME_COMPONENT(TARGET_PATH ${TARGET_LOC} PATH)
87 88
    ADD_CUSTOM_COMMAND(TARGET lp_test POST_BUILD
88 89
      COMMAND ${CMAKE_COMMAND} -E copy ${CPLEX_BIN_DIR}/cplex91.dll ${TARGET_PATH}
89 90
    )
90 91
  ENDIF()
91 92
ENDIF()
92 93

	
93 94
IF(LEMON_HAVE_MIP)
94 95
  IF(${CMAKE_BUILD_TYPE} STREQUAL "Maintainer")
95 96
    ADD_EXECUTABLE(mip_test mip_test.cc)
96 97
  ELSE()
97 98
    ADD_EXECUTABLE(mip_test EXCLUDE_FROM_ALL mip_test.cc)
98 99
  ENDIF()
99 100

	
100 101
  SET(MIP_TEST_LIBS lemon)
101 102

	
102 103
  IF(LEMON_HAVE_GLPK)
103 104
    SET(MIP_TEST_LIBS ${MIP_TEST_LIBS} ${GLPK_LIBRARIES})
104 105
  ENDIF()
105 106
  IF(LEMON_HAVE_CPLEX)
106 107
    SET(MIP_TEST_LIBS ${MIP_TEST_LIBS} ${CPLEX_LIBRARIES})
107 108
  ENDIF()
108 109
  IF(LEMON_HAVE_CBC)
109 110
    SET(MIP_TEST_LIBS ${MIP_TEST_LIBS} ${COIN_CBC_LIBRARIES})
110 111
  ENDIF()
111 112

	
112 113
  TARGET_LINK_LIBRARIES(mip_test ${MIP_TEST_LIBS})
113 114
  ADD_TEST(mip_test mip_test)
114 115
  ADD_DEPENDENCIES(check mip_test)
115 116

	
116 117
  IF(WIN32 AND LEMON_HAVE_GLPK)
117 118
    GET_TARGET_PROPERTY(TARGET_LOC mip_test LOCATION)
118 119
    GET_FILENAME_COMPONENT(TARGET_PATH ${TARGET_LOC} PATH)
119 120
    ADD_CUSTOM_COMMAND(TARGET mip_test POST_BUILD
120 121
      COMMAND ${CMAKE_COMMAND} -E copy ${GLPK_BIN_DIR}/glpk.dll ${TARGET_PATH}
121 122
      COMMAND ${CMAKE_COMMAND} -E copy ${GLPK_BIN_DIR}/libltdl3.dll ${TARGET_PATH}
122 123
      COMMAND ${CMAKE_COMMAND} -E copy ${GLPK_BIN_DIR}/zlib1.dll ${TARGET_PATH}
123 124
    )
124 125
  ENDIF()
125 126

	
126 127
  IF(WIN32 AND LEMON_HAVE_CPLEX)
127 128
    GET_TARGET_PROPERTY(TARGET_LOC mip_test LOCATION)
128 129
    GET_FILENAME_COMPONENT(TARGET_PATH ${TARGET_LOC} PATH)
129 130
    ADD_CUSTOM_COMMAND(TARGET mip_test POST_BUILD
130 131
      COMMAND ${CMAKE_COMMAND} -E copy ${CPLEX_BIN_DIR}/cplex91.dll ${TARGET_PATH}
131 132
    )
132 133
  ENDIF()
133 134
ENDIF()
134 135

	
135 136
FOREACH(TEST_NAME ${TESTS})
136 137
  IF(${CMAKE_BUILD_TYPE} STREQUAL "Maintainer")
137 138
    ADD_EXECUTABLE(${TEST_NAME} ${TEST_NAME}.cc)
138 139
  ELSE()
139 140
    ADD_EXECUTABLE(${TEST_NAME} EXCLUDE_FROM_ALL ${TEST_NAME}.cc)
140 141
  ENDIF()
141 142
  TARGET_LINK_LIBRARIES(${TEST_NAME} lemon)
142 143
    IF(TEST_WITH_VALGRIND)
143 144
      ADD_TEST(${TEST_NAME}
144 145
        valgrind --error-exitcode=1 ${VALGRIND_FLAGS}
145 146
        ${CMAKE_CURRENT_BINARY_DIR}/${TEST_NAME} )
146 147
    ELSE()
147 148
      ADD_TEST(${TEST_NAME} ${TEST_NAME})
148 149
    ENDIF()
149 150
  ADD_DEPENDENCIES(check ${TEST_NAME})
150 151
ENDFOREACH()
Show white space 3072 line context
1 1
if USE_VALGRIND
2 2
TESTS_ENVIRONMENT=$(top_srcdir)/scripts/valgrind-wrapper.sh
3 3
endif
4 4

	
5 5
EXTRA_DIST += \
6 6
	test/CMakeLists.txt
7 7

	
8 8
noinst_HEADERS += \
9 9
	test/graph_test.h \
10 10
	test/test_tools.h
11 11

	
12 12
check_PROGRAMS += \
13 13
	test/adaptors_test \
14 14
	test/bellman_ford_test \
15 15
	test/bfs_test \
16 16
	test/circulation_test \
17 17
	test/connectivity_test \
18 18
	test/counter_test \
19 19
	test/dfs_test \
20 20
	test/digraph_test \
21 21
	test/dijkstra_test \
22 22
	test/dim_test \
23 23
	test/edge_set_test \
24 24
	test/error_test \
25 25
	test/euler_test \
26 26
	test/fractional_matching_test \
27 27
	test/gomory_hu_test \
28 28
	test/graph_copy_test \
29 29
	test/graph_test \
30 30
	test/graph_utils_test \
31 31
	test/hao_orlin_test \
32 32
	test/heap_test \
33 33
	test/kruskal_test \
34
	test/lgf_test \
34 35
	test/maps_test \
35 36
	test/matching_test \
36 37
	test/min_cost_arborescence_test \
37 38
	test/min_cost_flow_test \
38 39
	test/min_mean_cycle_test \
39 40
	test/path_test \
40 41
	test/planarity_test \
41 42
	test/preflow_test \
42 43
	test/radix_sort_test \
43 44
	test/random_test \
44 45
	test/suurballe_test \
45 46
	test/test_tools_fail \
46 47
	test/test_tools_pass \
47 48
	test/time_measure_test \
48 49
	test/unionfind_test
49 50

	
50 51
test_test_tools_pass_DEPENDENCIES = demo
51 52

	
52 53
if HAVE_LP
53 54
check_PROGRAMS += test/lp_test
54 55
endif HAVE_LP
55 56
if HAVE_MIP
56 57
check_PROGRAMS += test/mip_test
57 58
endif HAVE_MIP
58 59

	
59 60
TESTS += $(check_PROGRAMS)
60 61
XFAIL_TESTS += test/test_tools_fail$(EXEEXT)
61 62

	
62 63
test_adaptors_test_SOURCES = test/adaptors_test.cc
63 64
test_bellman_ford_test_SOURCES = test/bellman_ford_test.cc
64 65
test_bfs_test_SOURCES = test/bfs_test.cc
65 66
test_circulation_test_SOURCES = test/circulation_test.cc
66 67
test_counter_test_SOURCES = test/counter_test.cc
67 68
test_connectivity_test_SOURCES = test/connectivity_test.cc
68 69
test_dfs_test_SOURCES = test/dfs_test.cc
69 70
test_digraph_test_SOURCES = test/digraph_test.cc
70 71
test_dijkstra_test_SOURCES = test/dijkstra_test.cc
71 72
test_dim_test_SOURCES = test/dim_test.cc
72 73
test_edge_set_test_SOURCES = test/edge_set_test.cc
73 74
test_error_test_SOURCES = test/error_test.cc
74 75
test_euler_test_SOURCES = test/euler_test.cc
75 76
test_fractional_matching_test_SOURCES = test/fractional_matching_test.cc
76 77
test_gomory_hu_test_SOURCES = test/gomory_hu_test.cc
77 78
test_graph_copy_test_SOURCES = test/graph_copy_test.cc
78 79
test_graph_test_SOURCES = test/graph_test.cc
79 80
test_graph_utils_test_SOURCES = test/graph_utils_test.cc
81
test_hao_orlin_test_SOURCES = test/hao_orlin_test.cc
80 82
test_heap_test_SOURCES = test/heap_test.cc
81 83
test_kruskal_test_SOURCES = test/kruskal_test.cc
82
test_hao_orlin_test_SOURCES = test/hao_orlin_test.cc
84
test_lgf_test_SOURCES = test/lgf_test.cc
83 85
test_lp_test_SOURCES = test/lp_test.cc
84 86
test_maps_test_SOURCES = test/maps_test.cc
85 87
test_mip_test_SOURCES = test/mip_test.cc
86 88
test_matching_test_SOURCES = test/matching_test.cc
87 89
test_min_cost_arborescence_test_SOURCES = test/min_cost_arborescence_test.cc
88 90
test_min_cost_flow_test_SOURCES = test/min_cost_flow_test.cc
89 91
test_min_mean_cycle_test_SOURCES = test/min_mean_cycle_test.cc
90 92
test_path_test_SOURCES = test/path_test.cc
91 93
test_planarity_test_SOURCES = test/planarity_test.cc
92 94
test_preflow_test_SOURCES = test/preflow_test.cc
93 95
test_radix_sort_test_SOURCES = test/radix_sort_test.cc
94 96
test_suurballe_test_SOURCES = test/suurballe_test.cc
95 97
test_random_test_SOURCES = test/random_test.cc
96 98
test_test_tools_fail_SOURCES = test/test_tools_fail.cc
97 99
test_test_tools_pass_SOURCES = test/test_tools_pass.cc
98 100
test_time_measure_test_SOURCES = test/time_measure_test.cc
99 101
test_unionfind_test_SOURCES = test/unionfind_test.cc
0 comments (0 inline)