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

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

	
23
using namespace lemon;
24

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

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

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

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

	
65

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

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

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

	
141
  {
142
    ListDigraph d; 
143
    std::istringstream input(test_lgf_bad2);
144
    bool ok=false;
145
    try {
146
      digraphReader(d, input).
147
        run();
148
    }
149
    catch (FormatError& error)
150
      {
151
        ok = true;
152
      }
153
    check(ok,"FormatError exception should have occured");
154
  }
155
  {
156
    ListGraph g;
157
    std::istringstream input(test_lgf_bad2);
158
    bool ok=false;
159
    try {
160
      graphReader(g, input).
161
        run();
162
    }
163
    catch (FormatError& error)
164
      {
165
        ok = true;
166
      }
167
    check(ok,"FormatError exception should have occured");
168
  }
169
}
Ignore white space 6 line context
1 1
/* -*- mode: C++; indent-tabs-mode: nil; -*-
2 2
 *
3 3
 * This file is a part of LEMON, a generic C++ optimization library.
4 4
 *
5 5
 * Copyright (C) 2003-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
Ignore white space 6 line context
1 1
/* -*- mode: C++; indent-tabs-mode: nil; -*-
2 2
 *
3 3
 * This file is a part of LEMON, a generic C++ optimization library.
4 4
 *
5
 * Copyright (C) 2003-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

	
... ...
@@ -583,768 +583,775 @@
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.
... ...
@@ -1453,768 +1460,775 @@
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
Ignore white space 768 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()
Ignore white space 6 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)