COIN-OR::LEMON - Graph Library

source: lemon-0.x/src/work/deba/graph_reader.h @ 1081:c0ad2673b11f

Last change on this file since 1081:c0ad2673b11f was 1037:3eaff8d04171, checked in by Balazs Dezso, 19 years ago

graph_io under construction
This is a working version, but needs more improvments.

todo:

documention + fix the file format
improve the exception system

add some possible asserts

tutorials

File size: 15.4 KB
Line 
1/* -*- C++ -*-
2 * src/lemon/graph_reader.h - Part of LEMON, a generic C++ optimization library
3 *
4 * Copyright (C) 2004 Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
5 * (Egervary Combinatorial Optimization Research Group, EGRES).
6 *
7 * Permission to use, modify and distribute this software is granted
8 * provided that this copyright notice appears in all copies. For
9 * precise terms see the accompanying LICENSE file.
10 *
11 * This software is provided "AS IS" with no warranty of any kind,
12 * express or implied, and with no claim as to its suitability for any
13 * purpose.
14 *
15 */
16
17///\ingroup gio
18///\file
19///\brief Graph reader.
20
21#include <iostream>
22#include <sstream>
23
24#include <map>
25#include <vector>
26
27#include <memory>
28
29#include <lemon/error.h>
30
31/// \todo fix exceptions
32
33
34namespace lemon {
35
36  // Exceptions
37
38  class IOException {
39  public:
40    virtual string what() const = 0;
41  };
42
43  class DataFormatException : public IOException {
44    std::string message;
45  public:
46    DataFormatException(const std::string& _message)
47      : message(_message) {}
48    std::string what() const {
49      return "DataFormatException: " + message;
50    }
51  };
52
53  template <typename _Exception>
54  class StreamException : public _Exception {
55  public:
56    typedef _Exception Exception;
57    StreamException(int _line, Exception _exception)
58      : line_num(_line), Exception(_exception) {}
59    virtual int line() const {
60      return line_num;
61    }
62    virtual std::string what() const {
63      ostringstream os;
64      os << Exception::what() << " in line " << line();
65      return os.str();
66    }
67  private:
68    int line_num;
69  }; 
70
71
72  // Readers and ReaderTraits
73 
74  struct DefaultReaderTraits {
75
76    template <typename _Value>
77    struct Reader {
78      typedef _Value Value;
79      void read(std::istream& is, Value& value) {
80        if (!(is >> value))
81          throw DataFormatException("Default Reader format exception");
82      }
83    };
84
85    typedef Reader<std::string> DefaultReader;
86
87  };
88
89  class QuotedStringReader {
90  public:
91    typedef std::string Value;
92
93    QuotedStringReader(bool _escaped = true) : escaped(_escaped) {}
94
95    void read(std::istream& is, std::string& value) {
96      char c;
97      value.clear();
98      is >> ws;
99      if (!is.get(c) || c != '\"') throw DataFormatException("Quoted string format");
100      while (is.get(c) && c != '\"') {
101        if (escaped && c == '\\') {
102          value += readEscape(is);
103        } else {
104          value += c;
105        }
106      }
107      if (!is) throw DataFormatException("Quoted string format");
108    }
109
110  private:
111   
112    static char readEscape(std::istream& is) {
113      char c;
114      switch (is.get(c), c) {
115      case '\\':
116        return '\\';
117      case '\"':
118        return '\"';
119      case '\'':
120        return '\'';
121      case '\?':
122        return '\?';
123      case 'a':
124        return '\a';
125      case 'b':
126        return '\b';
127      case 'f':
128        return '\f';
129      case 'n':
130        return '\n';
131      case 'r':
132        return '\r';
133      case 't':
134        return '\t';
135      case 'v':
136        return '\v';
137      case 'x':
138        {
139          int code;
140          if (!is.get(c) || !isHex(c)) throw DataFormatException("Escape format exception");
141          else if (code = valueHex(c), !is.get(c) || !isHex(c)) is.putback(c);
142          else code = code * 16 + valueHex(c);
143          return code;
144        }
145      default:
146        {
147          int code;
148          if (!isOct(c)) throw DataFormatException("Escape format exception");
149          else if (code = valueOct(c), !is.get(c) || !isOct(c)) is.putback(c);
150          else if (code = code * 8 + valueOct(c), !is.get(c) || !isOct(c)) is.putback(c);
151          else code = code * 8 + valueOct(c);
152          return code;
153        }             
154      }
155    }
156
157    static bool isOct(char c) {
158      return '0' <= c && c <='7';
159    }
160   
161    static int valueOct(char c) {
162      return c - '0';
163    }
164
165   static bool isHex(char c) {
166      return ('0' <= c && c <= '9') || ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z');
167    }
168   
169    static int valueHex(char c) {
170      if ('0' <= c && c <= '9') return c - '0';
171      if ('a' <= c && c <= 'z') return c - 'a' + 10;
172      return c - 'A' + 10;
173    }
174
175    bool escaped;
176  };
177
178
179
180
181
182  // Graph reader
183 
184  template <typename _Graph, typename _ReaderTraits = DefaultReaderTraits>
185  class GraphReader {
186  public:
187   
188    typedef _Graph Graph;
189    typedef typename Graph::Node Node;
190    typedef typename Graph::Edge Edge;
191
192    typedef _ReaderTraits ReaderTraits;
193    typedef typename ReaderTraits::DefaultReader DefaultReader;
194
195    GraphReader(std::istream& _is, Graph& _graph, const DefaultReader& _reader = DefaultReader())
196      : is(_is), graph(_graph), nodeSkipper(_reader), edgeSkipper(_reader) {}
197
198
199    ~GraphReader() {
200
201      for (typename NodeMapReaders::iterator it = node_map_readers.begin(); it != node_map_readers.end(); ++it) {
202        delete it->second;
203      }
204
205      for (typename EdgeMapReaders::iterator it = edge_map_readers.begin(); it != edge_map_readers.end(); ++it) {
206        delete it->second;
207      }
208
209    }
210
211    // Node map rules
212
213    template <typename Map>
214    GraphReader& readNodeMap(std::string name, Map& map) {
215      return readNodeMap<typename ReaderTraits::template Reader<typename Map::Value>, Map>(name, map);
216    }
217
218    template <typename Reader, typename Map>
219    GraphReader& readNodeMap(std::string name, Map& map, const Reader& reader = Reader()) {
220      if (node_map_readers.find(name) != node_map_readers.end()) {
221        throw Exception() << "Multiple read rule for node map: " << name;
222      }
223      node_map_readers.insert(make_pair(name, new MapReader<Node, Map, Reader>(map, reader)));
224      return *this;
225    }
226
227    template <typename Reader>
228    GraphReader& skipNodeMap(std::string name, const Reader& reader = Reader()) {
229      if (node_map_readers.find(name) != node_map_readers.end()) {
230        throw Exception() << "Multiple read rule for node map: " << name;
231      }
232      node_map_readers.insert(make_pair(name, new SkipReader<Node, Reader>(reader)));
233      return *this;
234    }
235
236    // Edge map rules
237
238    template <typename Map>
239    GraphReader& readEdgeMap(std::string name, Map& map) {
240      return readEdgeMap<typename ReaderTraits::template Reader<typename Map::Value>, Map>(name, map);
241    }
242
243
244    template <typename Reader, typename Map>
245    GraphReader& readEdgeMap(std::string name, Map& map, const Reader& reader = Reader()) {
246      if (edge_map_readers.find(name) != edge_map_readers.end()) {
247        throw Exception() << "Multiple read rule for edge map: " << name;
248      }
249      edge_map_readers.insert(make_pair(name, new MapReader<Edge, Map, Reader>(map, reader)));
250      return *this;
251    }
252
253    template <typename Reader>
254    GraphReader& skipEdgeMap(std::string name, const Reader& reader = Reader()) {
255      if (edge_map_readers.find(name) != edge_map_readers.end()) {
256        throw Exception() << "Multiple read rule for edge map: " << name;
257      }
258      edge_map_readers.insert(make_pair(name, new SkipReader<Edge, Reader>(reader)));
259      return *this;
260    }
261
262    // Node rules
263    GraphReader& readNode(std::string name, Node& node) {
264      if (node_readers.find(name) != node_readers.end()) {
265        throw Exception() << "Multiple read rule for node";
266      }
267      node_readers.insert(make_pair(name, &node));
268    }
269
270    // Edge rules
271
272    GraphReader& readEdge(std::string name, Edge& edge) {
273      if (edge_readers.find(name) != edge_readers.end()) {
274        throw Exception() << "Multiple read rule for edge";
275      }
276      edge_readers.insert(make_pair(name, &edge));
277    }
278
279    void read() {
280      int line_num = 0;
281      std::auto_ptr<InverterBase<Node> > nodeInverter;
282      std::auto_ptr<InverterBase<Edge> > edgeInverter;
283      try {
284        std::string line = readNotEmptyLine(is, line_num);
285        if (line.find("@nodeset") == 0) {
286          line = readNodeSet(line_num, nodeInverter);
287        }
288        if (line.find("@edgeset") == 0) {
289          line = readEdgeSet(line_num, edgeInverter, nodeInverter);
290        }
291        if (line.find("@nodes") == 0) {
292          line = readNodes(line_num, nodeInverter);
293        }
294        if (line.find("@edges") == 0) {
295          line = readEdges(line_num, edgeInverter);
296        }
297        if (line.find("@end") != 0) {
298          throw DataFormatException("Invalid control sequence: " + line);
299        }
300      } catch (DataFormatException e) {
301        throw StreamException<DataFormatException>(line_num, e);
302      }
303    }
304
305  private:
306
307    template <typename Item> class InverterBase;
308
309    std::string readNodeSet(int& line_num, auto_ptr<InverterBase<Node> > & nodeInverter) {
310      std::vector<ReaderBase<Node>* > index;
311      {
312        std::string line = readNotEmptyLine(is, line_num);   
313        std::string id;
314        std::istringstream ls(line);   
315        while (ls >> id) {
316          if (id[0] == '#') break;
317          typename NodeMapReaders::iterator it = node_map_readers.find(id);
318          if (it != node_map_readers.end()) {
319            index.push_back(it->second);
320            node_map_readers.erase(it);
321          } else {
322            index.push_back(&nodeSkipper);
323          }
324        }
325      }
326
327      if (index.size() == 0) {
328        throw DataFormatException("No node map found");
329      }
330
331      nodeInverter = auto_ptr<InverterBase<Node> >(index[0]->getInverter());
332      std::string line;
333      while (line = readNotEmptyLine(is, line_num), line[0] != '@') {
334        Node node = graph.addNode();
335        std::istringstream ls(line);
336        nodeInverter->read(ls, node);
337        for (int i = 1; i < index.size(); ++i) {
338          index[i]->read(ls, node);
339        }
340      }
341      return line;
342    }
343
344    std::string readEdgeSet(int& line_num,
345                     auto_ptr<InverterBase<Edge> > & edgeInverter, auto_ptr<InverterBase<Node> > & nodeInverter) {
346      std::vector<ReaderBase<Edge>*> index;
347      {
348        std::string line = readNotEmptyLine(is, line_num);   
349        std::string id;
350        std::istringstream ls(line);   
351        while (ls >> id) {
352          if (id[0] == '#') break;
353          typename EdgeMapReaders::iterator it = edge_map_readers.find(id);
354          if (it != edge_map_readers.end()) {
355            index.push_back(it->second);
356            edge_map_readers.erase(it);
357          } else {
358            index.push_back(&edgeSkipper);
359          }
360        }
361      }
362
363      if (index.size() == 0) {
364        throw DataFormatException("No edge map found");
365      }
366
367      edgeInverter = auto_ptr<InverterBase<Edge> >(index[0]->getInverter());
368      std::string line;
369      while (line = readNotEmptyLine(is, line_num), line[0] != '@') {   
370        std::istringstream ls(line);
371        Node source = nodeInverter->read(ls);
372        Node target = nodeInverter->read(ls);
373        Edge edge = graph.addEdge(source, target);
374        edgeInverter->read(ls, edge);
375        for (int i = 1; i < index.size(); ++i) {
376          index[i]->read(ls, edge);
377        }
378      }     
379      return line;
380    }
381
382    std::string readNodes(int& line_num, auto_ptr<InverterBase<Node> >& nodeInverter) {
383      std::string line;
384      while (line = readNotEmptyLine(is, line_num), line[0] != '@') {
385        std::istringstream ls(line);
386        std::string name;
387        ls >> name;
388        typename NodeReaders::iterator it = node_readers.find(name);
389        if (it != node_readers.end()) {
390          *(it -> second) = nodeInverter->read(ls);
391        }
392      }       
393      return line;
394    }
395
396    std::string readEdges(int& line_num, auto_ptr<InverterBase<Edge> >& edgeInverter) {
397      std::string line;
398      while (line = readNotEmptyLine(is, line_num), line[0] != '@') {
399        std::istringstream ls(line);
400        std::string name;
401        ls >> name;
402        typename EdgeReaders::iterator it = edge_readers.find(name);
403        if (it != edge_readers.end()) {
404          *(it -> second) = edgeInverter->read(ls);
405        }
406      }       
407      return line;   
408    }
409
410    std::string readNotEmptyLine(std::istream& is, int& line_num) {
411      std::string line;
412      while (++line_num, getline(is, line)) {   
413        int vi = line.find_first_not_of(" \t");
414        if (vi != string::npos && line[vi] != '#') {
415          return line.substr(vi);
416        }
417      }
418      throw DataFormatException("End of stream");
419    }
420   
421    // Inverters store and give back the Item from the id,
422    // and may put the ids into a map.
423   
424    template <typename _Item>
425    class InverterBase {
426    public:
427      typedef _Item Item;
428      virtual void read(std::istream&, const Item&) = 0;
429      virtual Item read(std::istream&) = 0;
430    };
431
432    template <typename _Item, typename _Map, typename _Reader>
433    class MapReaderInverter : public InverterBase<_Item> {
434    public:
435      typedef _Item Item;
436      typedef _Reader Reader;
437      typedef typename Reader::Value Value;
438      typedef _Map Map;
439      typedef std::map<Value, Item> Inverse;
440
441      Map& map;
442      Reader reader;
443      Inverse inverse;
444
445      MapReaderInverter(Map& _map, const Reader& _reader)
446        : map(_map), reader(_reader) {}
447
448      virtual void read(std::istream& is, const Item& item) {
449        Value value;
450        reader.read(is, value);
451        map.set(item, value);
452        typename Inverse::iterator it = inverse.find(value);
453        if (it == inverse.end()) {
454          inverse.insert(make_pair(value, item));
455        } else {
456          throw DataFormatException("Multiple ID occurence");
457        }
458      }
459
460      virtual Item read(std::istream& is) {
461        Value value;
462        reader.read(is, value);
463        typename Inverse::const_iterator it = inverse.find(value);
464        if (it != inverse.end()) {
465          return it->second;
466        } else {
467          throw DataFormatException("Invalid ID");
468        }
469      }     
470    };
471
472    template <typename _Item, typename _Reader>
473    class SkipReaderInverter : public InverterBase<_Item> {
474    public:
475      typedef _Item Item;
476      typedef _Reader Reader;
477      typedef typename Reader::Value Value;
478      typedef std::map<Value, Item> Inverse;
479
480      Reader reader;
481
482      SkipReaderInverter(const Reader& _reader)
483        : reader(_reader) {}
484
485      virtual void read(std::istream& is, const Item& item) {
486        Value value;
487        reader.read(is, value);
488        typename Inverse::iterator it = inverse.find(value);
489        if (it == inverse.end()) {
490          inverse.insert(make_pair(value, item));
491        } else {
492          throw DataFormatException("Multiple ID occurence");
493        }
494      }
495
496      virtual Item read(std::istream& is) {
497        Value value;
498        reader.read(is, value);
499        typename Inverse::const_iterator it = inverse.find(value);
500        if (it != inverse.end()) {
501          return it->second;
502        } else {
503          throw DataFormatException("Invalid ID");
504        }
505      }     
506    private:
507      Inverse inverse;
508    };
509
510    // Readers
511
512    template <typename _Item>   
513    class ReaderBase {
514    public:
515      typedef _Item Item;
516
517      virtual void read(std::istream& is, const Item& item) = 0;
518      virtual InverterBase<_Item>* getInverter() = 0;
519    };
520
521    template <typename _Item, typename _Map, typename _Reader>
522    class MapReader : public ReaderBase<_Item> {
523    public:
524      typedef _Map Map;
525      typedef _Reader Reader;
526      typedef typename Reader::Value Value;
527      typedef _Item Item;
528     
529      Map& map;
530      Reader reader;
531
532      MapReader(Map& _map, const Reader& _reader)
533        : map(_map), reader(_reader) {}
534
535
536      virtual void read(std::istream& is, const Item& item) {
537        Value value;
538        reader.read(is, value);
539        map.set(item, value);
540      }
541
542      virtual InverterBase<_Item>* getInverter() {
543        return new MapReaderInverter<Item, Map, Reader>(map, reader);
544      }
545    };
546
547
548    template <typename _Item, typename _Reader>
549    class SkipReader : public ReaderBase<_Item> {
550    public:
551      typedef _Reader Reader;
552      typedef typename Reader::Value Value;
553      typedef _Item Item;
554
555      Reader reader;
556      SkipReader(const Reader& _reader) : reader(_reader) {}
557
558      virtual void read(std::istream& is, const Item& item) {
559        Value value;
560        reader.read(is, value);
561      }     
562
563      virtual InverterBase<Item>* getInverter() {
564        return new SkipReaderInverter<Item, Reader>(reader);
565      }
566    };
567
568
569    typedef std::map<std::string, ReaderBase<Node>*> NodeMapReaders;
570    NodeMapReaders node_map_readers;
571
572    typedef std::map<std::string, ReaderBase<Edge>*> EdgeMapReaders;
573    EdgeMapReaders edge_map_readers;
574
575    typedef std::map<std::string, Node*> NodeReaders;
576    NodeReaders node_readers;
577
578    typedef std::map<std::string, Edge*> EdgeReaders;
579    EdgeReaders edge_readers;
580
581    std::istream& is;
582    Graph& graph;
583
584    SkipReader<Node, DefaultReader> nodeSkipper;
585    SkipReader<Edge, DefaultReader> edgeSkipper;
586
587  };
588
589}
Note: See TracBrowser for help on using the repository browser.