COIN-OR::LEMON - Graph Library

source: lemon/lemon/lgf_writer.h @ 461:1229dc2f1d36

Last change on this file since 461:1229dc2f1d36 was 319:5e12d7734036, checked in by Alpar Juttner <alpar@…>, 15 years ago

arrert.h is now included by core.h (#161)

File size: 51.3 KB
RevLine 
[209]1/* -*- mode: C++; indent-tabs-mode: nil; -*-
[127]2 *
[209]3 * This file is a part of LEMON, a generic C++ optimization library.
[127]4 *
5 * Copyright (C) 2003-2008
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///\ingroup lemon_io
20///\file
[236]21///\brief \ref lgf-format "LEMON Graph Format" writer.
[127]22
23
24#ifndef LEMON_LGF_WRITER_H
25#define LEMON_LGF_WRITER_H
26
27#include <iostream>
28#include <fstream>
29#include <sstream>
30
31#include <algorithm>
32
33#include <vector>
34#include <functional>
35
[220]36#include <lemon/core.h>
37#include <lemon/maps.h>
[127]38
[248]39#include <lemon/concept_check.h>
40#include <lemon/concepts/maps.h>
41
[127]42namespace lemon {
43
44  namespace _writer_bits {
45
46    template <typename Value>
47    struct DefaultConverter {
48      std::string operator()(const Value& value) {
[209]49        std::ostringstream os;
50        os << value;
51        return os.str();
[127]52      }
53    };
54
55    template <typename T>
56    bool operator<(const T&, const T&) {
[290]57      throw FormatError("Label map is not comparable");
[127]58    }
59
60    template <typename _Map>
61    class MapLess {
62    public:
63      typedef _Map Map;
64      typedef typename Map::Key Item;
65
66    private:
67      const Map& _map;
[209]68
[127]69    public:
70      MapLess(const Map& map) : _map(map) {}
71
72      bool operator()(const Item& left, const Item& right) {
[209]73        return _map[left] < _map[right];
[127]74      }
75    };
76
[165]77    template <typename _Graph, bool _dir, typename _Map>
78    class GraphArcMapLess {
79    public:
80      typedef _Map Map;
81      typedef _Graph Graph;
82      typedef typename Graph::Edge Item;
83
84    private:
85      const Graph& _graph;
86      const Map& _map;
[209]87
[165]88    public:
[209]89      GraphArcMapLess(const Graph& graph, const Map& map)
90        : _graph(graph), _map(map) {}
[165]91
92      bool operator()(const Item& left, const Item& right) {
[209]93        return _map[_graph.direct(left, _dir)] <
94          _map[_graph.direct(right, _dir)];
[165]95      }
96    };
97
[209]98    template <typename _Item>
[127]99    class MapStorageBase {
100    public:
101      typedef _Item Item;
102
103    public:
104      MapStorageBase() {}
105      virtual ~MapStorageBase() {}
106
107      virtual std::string get(const Item& item) = 0;
108      virtual void sort(std::vector<Item>&) = 0;
109    };
110
[209]111    template <typename _Item, typename _Map,
112              typename _Converter = DefaultConverter<typename _Map::Value> >
[127]113    class MapStorage : public MapStorageBase<_Item> {
114    public:
115      typedef _Map Map;
116      typedef _Converter Converter;
117      typedef _Item Item;
[209]118
[127]119    private:
120      const Map& _map;
121      Converter _converter;
122
123    public:
[209]124      MapStorage(const Map& map, const Converter& converter = Converter())
125        : _map(map), _converter(converter) {}
[127]126      virtual ~MapStorage() {}
127
128      virtual std::string get(const Item& item) {
[209]129        return _converter(_map[item]);
[127]130      }
131      virtual void sort(std::vector<Item>& items) {
[209]132        MapLess<Map> less(_map);
133        std::sort(items.begin(), items.end(), less);
[127]134      }
135    };
136
[209]137    template <typename _Graph, bool _dir, typename _Map,
138              typename _Converter = DefaultConverter<typename _Map::Value> >
[165]139    class GraphArcMapStorage : public MapStorageBase<typename _Graph::Edge> {
140    public:
141      typedef _Map Map;
142      typedef _Converter Converter;
143      typedef _Graph Graph;
144      typedef typename Graph::Edge Item;
145      static const bool dir = _dir;
[209]146
[165]147    private:
148      const Graph& _graph;
149      const Map& _map;
150      Converter _converter;
151
152    public:
[209]153      GraphArcMapStorage(const Graph& graph, const Map& map,
154                         const Converter& converter = Converter())
155        : _graph(graph), _map(map), _converter(converter) {}
[165]156      virtual ~GraphArcMapStorage() {}
157
158      virtual std::string get(const Item& item) {
[209]159        return _converter(_map[_graph.direct(item, dir)]);
[165]160      }
161      virtual void sort(std::vector<Item>& items) {
[209]162        GraphArcMapLess<Graph, dir, Map> less(_graph, _map);
163        std::sort(items.begin(), items.end(), less);
[165]164      }
165    };
166
[127]167    class ValueStorageBase {
168    public:
169      ValueStorageBase() {}
170      virtual ~ValueStorageBase() {}
171
[209]172      virtual std::string get() = 0;
[127]173    };
174
175    template <typename _Value, typename _Converter = DefaultConverter<_Value> >
176    class ValueStorage : public ValueStorageBase {
177    public:
178      typedef _Value Value;
179      typedef _Converter Converter;
180
181    private:
182      const Value& _value;
183      Converter _converter;
184
185    public:
186      ValueStorage(const Value& value, const Converter& converter = Converter())
[212]187        : _value(value), _converter(converter) {}
[127]188
189      virtual std::string get() {
[209]190        return _converter(_value);
[127]191      }
192    };
193
194    template <typename Value>
195    struct MapLookUpConverter {
196      const std::map<Value, std::string>& _map;
[209]197
198      MapLookUpConverter(const std::map<Value, std::string>& map)
199        : _map(map) {}
200
[127]201      std::string operator()(const Value& str) {
[209]202        typename std::map<Value, std::string>::const_iterator it =
203          _map.find(str);
204        if (it == _map.end()) {
[290]205          throw FormatError("Item not found");
[209]206        }
207        return it->second;
[127]208      }
209    };
210
[165]211    template <typename Graph>
212    struct GraphArcLookUpConverter {
213      const Graph& _graph;
214      const std::map<typename Graph::Edge, std::string>& _map;
[209]215
216      GraphArcLookUpConverter(const Graph& graph,
217                              const std::map<typename Graph::Edge,
218                                             std::string>& map)
219        : _graph(graph), _map(map) {}
220
[165]221      std::string operator()(const typename Graph::Arc& val) {
[209]222        typename std::map<typename Graph::Edge, std::string>
223          ::const_iterator it = _map.find(val);
224        if (it == _map.end()) {
[290]225          throw FormatError("Item not found");
[209]226        }
227        return (_graph.direction(val) ? '+' : '-') + it->second;
[165]228      }
229    };
230
[197]231    inline bool isWhiteSpace(char c) {
[209]232      return c == ' ' || c == '\t' || c == '\v' ||
233        c == '\n' || c == '\r' || c == '\f';
[127]234    }
235
[197]236    inline bool isEscaped(char c) {
[209]237      return c == '\\' || c == '\"' || c == '\'' ||
238        c == '\a' || c == '\b';
[127]239    }
240
[197]241    inline static void writeEscape(std::ostream& os, char c) {
[127]242      switch (c) {
243      case '\\':
[209]244        os << "\\\\";
245        return;
[127]246      case '\"':
[209]247        os << "\\\"";
248        return;
[127]249      case '\a':
[209]250        os << "\\a";
251        return;
[127]252      case '\b':
[209]253        os << "\\b";
254        return;
[127]255      case '\f':
[209]256        os << "\\f";
257        return;
[127]258      case '\r':
[209]259        os << "\\r";
260        return;
[127]261      case '\n':
[209]262        os << "\\n";
263        return;
[127]264      case '\t':
[209]265        os << "\\t";
266        return;
[127]267      case '\v':
[209]268        os << "\\v";
269        return;
[127]270      default:
[209]271        if (c < 0x20) {
272          std::ios::fmtflags flags = os.flags();
273          os << '\\' << std::oct << static_cast<int>(c);
274          os.flags(flags);
275        } else {
276          os << c;
277        }
278        return;
279      }
[127]280    }
281
[197]282    inline bool requireEscape(const std::string& str) {
[156]283      if (str.empty() || str[0] == '@') return true;
[127]284      std::istringstream is(str);
285      char c;
286      while (is.get(c)) {
[209]287        if (isWhiteSpace(c) || isEscaped(c)) {
288          return true;
289        }
[127]290      }
291      return false;
292    }
[209]293
[197]294    inline std::ostream& writeToken(std::ostream& os, const std::string& str) {
[127]295
296      if (requireEscape(str)) {
[209]297        os << '\"';
298        for (std::string::const_iterator it = str.begin();
299             it != str.end(); ++it) {
300          writeEscape(os, *it);
301        }
302        os << '\"';
[127]303      } else {
[209]304        os << str;
[127]305      }
306      return os;
307    }
308
[248]309    class Section {
310    public:
311      virtual ~Section() {}
312      virtual void process(std::ostream& os) = 0;
313    };
314
315    template <typename Functor>
316    class LineSection : public Section {
317    private:
318
319      Functor _functor;
320
321    public:
322
323      LineSection(const Functor& functor) : _functor(functor) {}
324      virtual ~LineSection() {}
325
326      virtual void process(std::ostream& os) {
327        std::string line;
328        while (!(line = _functor()).empty()) os << line << std::endl;
329      }
330    };
331
332    template <typename Functor>
333    class StreamSection : public Section {
334    private:
335
336      Functor _functor;
337
338    public:
339
340      StreamSection(const Functor& functor) : _functor(functor) {}
341      virtual ~StreamSection() {}
342
343      virtual void process(std::ostream& os) {
344        _functor(os);
345      }
346    };
347
[127]348  }
[190]349
350  template <typename Digraph>
351  class DigraphWriter;
352
[303]353  /// \brief Return a \ref DigraphWriter class
354  ///
355  /// This function just returns a \ref DigraphWriter class.
356  /// \relates DigraphWriter
[190]357  template <typename Digraph>
[293]358  DigraphWriter<Digraph> digraphWriter(const Digraph& digraph,
[303]359                                       std::ostream& os = std::cout) {
360    DigraphWriter<Digraph> tmp(digraph, os);
361    return tmp;
362  }
[190]363
[303]364  /// \brief Return a \ref DigraphWriter class
365  ///
366  /// This function just returns a \ref DigraphWriter class.
367  /// \relates DigraphWriter
[190]368  template <typename Digraph>
[293]369  DigraphWriter<Digraph> digraphWriter(const Digraph& digraph,
[303]370                                       const std::string& fn) {
371    DigraphWriter<Digraph> tmp(digraph, fn);
372    return tmp;
373  }
[190]374
[303]375  /// \brief Return a \ref DigraphWriter class
376  ///
377  /// This function just returns a \ref DigraphWriter class.
378  /// \relates DigraphWriter
[190]379  template <typename Digraph>
[293]380  DigraphWriter<Digraph> digraphWriter(const Digraph& digraph,
[303]381                                       const char* fn) {
382    DigraphWriter<Digraph> tmp(digraph, fn);
383    return tmp;
384  }
[209]385
[156]386  /// \ingroup lemon_io
[209]387  ///
[192]388  /// \brief \ref lgf-format "LGF" writer for directed graphs
[156]389  ///
390  /// This utility writes an \ref lgf-format "LGF" file.
391  ///
392  /// The writing method does a batch processing. The user creates a
393  /// writer object, then various writing rules can be added to the
394  /// writer, and eventually the writing is executed with the \c run()
395  /// member function. A map writing rule can be added to the writer
396  /// with the \c nodeMap() or \c arcMap() members. An optional
[163]397  /// converter parameter can also be added as a standard functor
[192]398  /// converting from the value type of the map to \c std::string. If it
399  /// is set, it will determine how the value type of the map is written to
[163]400  /// the output stream. If the functor is not set, then a default
401  /// conversion will be used. The \c attribute(), \c node() and \c
402  /// arc() functions are used to add attribute writing rules.
[156]403  ///
404  ///\code
[293]405  /// DigraphWriter<Digraph>(digraph, std::cout).
[192]406  ///   nodeMap("coordinates", coord_map).
407  ///   nodeMap("size", size).
408  ///   nodeMap("title", title).
409  ///   arcMap("capacity", cap_map).
410  ///   node("source", src).
411  ///   node("target", trg).
412  ///   attribute("caption", caption).
413  ///   run();
[156]414  ///\endcode
415  ///
416  ///
417  /// By default, the writer does not write additional captions to the
418  /// sections, but they can be give as an optional parameter of
419  /// the \c nodes(), \c arcs() or \c
420  /// attributes() functions.
421  ///
422  /// The \c skipNodes() and \c skipArcs() functions forbid the
[163]423  /// writing of the sections. If two arc sections should be written
424  /// to the output, it can be done in two passes, the first pass
425  /// writes the node section and the first arc section, then the
426  /// second pass skips the node section and writes just the arc
427  /// section to the stream. The output stream can be retrieved with
428  /// the \c ostream() function, hence the second pass can append its
429  /// output to the output of the first pass.
[127]430  template <typename _Digraph>
431  class DigraphWriter {
432  public:
433
434    typedef _Digraph Digraph;
[148]435    TEMPLATE_DIGRAPH_TYPEDEFS(Digraph);
[209]436
[127]437  private:
438
439
440    std::ostream* _os;
441    bool local_os;
442
[190]443    const Digraph& _digraph;
[127]444
445    std::string _nodes_caption;
446    std::string _arcs_caption;
447    std::string _attributes_caption;
[209]448
[127]449    typedef std::map<Node, std::string> NodeIndex;
450    NodeIndex _node_index;
451    typedef std::map<Arc, std::string> ArcIndex;
452    ArcIndex _arc_index;
453
[209]454    typedef std::vector<std::pair<std::string,
455      _writer_bits::MapStorageBase<Node>* > > NodeMaps;
456    NodeMaps _node_maps;
[127]457
[209]458    typedef std::vector<std::pair<std::string,
[127]459      _writer_bits::MapStorageBase<Arc>* > >ArcMaps;
460    ArcMaps _arc_maps;
461
[209]462    typedef std::vector<std::pair<std::string,
[127]463      _writer_bits::ValueStorageBase*> > Attributes;
464    Attributes _attributes;
465
466    bool _skip_nodes;
467    bool _skip_arcs;
468
469  public:
470
[156]471    /// \brief Constructor
472    ///
473    /// Construct a directed graph writer, which writes to the given
474    /// output stream.
[293]475    DigraphWriter(const Digraph& digraph, std::ostream& os = std::cout)
476      : _os(&os), local_os(false), _digraph(digraph),
[209]477        _skip_nodes(false), _skip_arcs(false) {}
[127]478
[156]479    /// \brief Constructor
480    ///
481    /// Construct a directed graph writer, which writes to the given
482    /// output file.
[293]483    DigraphWriter(const Digraph& digraph, const std::string& fn)
[127]484      : _os(new std::ofstream(fn.c_str())), local_os(true), _digraph(digraph),
[290]485        _skip_nodes(false), _skip_arcs(false) {
[295]486      if (!(*_os)) {
487        delete _os;
488        throw IoError("Cannot write file", fn);
489      }
[290]490    }
[127]491
[156]492    /// \brief Constructor
493    ///
494    /// Construct a directed graph writer, which writes to the given
495    /// output file.
[293]496    DigraphWriter(const Digraph& digraph, const char* fn)
[127]497      : _os(new std::ofstream(fn)), local_os(true), _digraph(digraph),
[290]498        _skip_nodes(false), _skip_arcs(false) {
[295]499      if (!(*_os)) {
500        delete _os;
501        throw IoError("Cannot write file", fn);
502      }
[290]503    }
[127]504
[156]505    /// \brief Destructor
[127]506    ~DigraphWriter() {
[209]507      for (typename NodeMaps::iterator it = _node_maps.begin();
508           it != _node_maps.end(); ++it) {
509        delete it->second;
[127]510      }
511
[209]512      for (typename ArcMaps::iterator it = _arc_maps.begin();
513           it != _arc_maps.end(); ++it) {
514        delete it->second;
[127]515      }
516
[209]517      for (typename Attributes::iterator it = _attributes.begin();
518           it != _attributes.end(); ++it) {
519        delete it->second;
[127]520      }
521
522      if (local_os) {
[209]523        delete _os;
[127]524      }
525    }
526
527  private:
[190]528
[293]529    friend DigraphWriter<Digraph> digraphWriter<>(const Digraph& digraph,
530                                                  std::ostream& os);
531    friend DigraphWriter<Digraph> digraphWriter<>(const Digraph& digraph,
532                                                  const std::string& fn);
533    friend DigraphWriter<Digraph> digraphWriter<>(const Digraph& digraph,
534                                                  const char *fn);
[190]535
[209]536    DigraphWriter(DigraphWriter& other)
[190]537      : _os(other._os), local_os(other.local_os), _digraph(other._digraph),
[209]538        _skip_nodes(other._skip_nodes), _skip_arcs(other._skip_arcs) {
[190]539
540      other._os = 0;
541      other.local_os = false;
542
543      _node_index.swap(other._node_index);
544      _arc_index.swap(other._arc_index);
545
546      _node_maps.swap(other._node_maps);
547      _arc_maps.swap(other._arc_maps);
548      _attributes.swap(other._attributes);
549
550      _nodes_caption = other._nodes_caption;
551      _arcs_caption = other._arcs_caption;
552      _attributes_caption = other._attributes_caption;
553    }
[209]554
[127]555    DigraphWriter& operator=(const DigraphWriter&);
556
557  public:
558
[156]559    /// \name Writing rules
560    /// @{
[209]561
[192]562    /// \brief Node map writing rule
[156]563    ///
[192]564    /// Add a node map writing rule to the writer.
[127]565    template <typename Map>
566    DigraphWriter& nodeMap(const std::string& caption, const Map& map) {
567      checkConcept<concepts::ReadMap<Node, typename Map::Value>, Map>();
[209]568      _writer_bits::MapStorageBase<Node>* storage =
569        new _writer_bits::MapStorage<Node, Map>(map);
[127]570      _node_maps.push_back(std::make_pair(caption, storage));
571      return *this;
572    }
573
[156]574    /// \brief Node map writing rule
575    ///
576    /// Add a node map writing rule with specialized converter to the
577    /// writer.
[127]578    template <typename Map, typename Converter>
[209]579    DigraphWriter& nodeMap(const std::string& caption, const Map& map,
580                           const Converter& converter = Converter()) {
[127]581      checkConcept<concepts::ReadMap<Node, typename Map::Value>, Map>();
[209]582      _writer_bits::MapStorageBase<Node>* storage =
583        new _writer_bits::MapStorage<Node, Map, Converter>(map, converter);
[127]584      _node_maps.push_back(std::make_pair(caption, storage));
585      return *this;
586    }
587
[156]588    /// \brief Arc map writing rule
589    ///
590    /// Add an arc map writing rule to the writer.
[127]591    template <typename Map>
592    DigraphWriter& arcMap(const std::string& caption, const Map& map) {
593      checkConcept<concepts::ReadMap<Arc, typename Map::Value>, Map>();
[209]594      _writer_bits::MapStorageBase<Arc>* storage =
595        new _writer_bits::MapStorage<Arc, Map>(map);
[127]596      _arc_maps.push_back(std::make_pair(caption, storage));
597      return *this;
598    }
599
[156]600    /// \brief Arc map writing rule
601    ///
602    /// Add an arc map writing rule with specialized converter to the
603    /// writer.
[127]604    template <typename Map, typename Converter>
[209]605    DigraphWriter& arcMap(const std::string& caption, const Map& map,
606                          const Converter& converter = Converter()) {
[127]607      checkConcept<concepts::ReadMap<Arc, typename Map::Value>, Map>();
[209]608      _writer_bits::MapStorageBase<Arc>* storage =
609        new _writer_bits::MapStorage<Arc, Map, Converter>(map, converter);
[127]610      _arc_maps.push_back(std::make_pair(caption, storage));
611      return *this;
612    }
613
[156]614    /// \brief Attribute writing rule
615    ///
616    /// Add an attribute writing rule to the writer.
[127]617    template <typename Value>
618    DigraphWriter& attribute(const std::string& caption, const Value& value) {
[209]619      _writer_bits::ValueStorageBase* storage =
620        new _writer_bits::ValueStorage<Value>(value);
[127]621      _attributes.push_back(std::make_pair(caption, storage));
622      return *this;
623    }
624
[156]625    /// \brief Attribute writing rule
626    ///
627    /// Add an attribute writing rule with specialized converter to the
628    /// writer.
[127]629    template <typename Value, typename Converter>
[209]630    DigraphWriter& attribute(const std::string& caption, const Value& value,
631                             const Converter& converter = Converter()) {
632      _writer_bits::ValueStorageBase* storage =
633        new _writer_bits::ValueStorage<Value, Converter>(value, converter);
[127]634      _attributes.push_back(std::make_pair(caption, storage));
635      return *this;
636    }
637
[156]638    /// \brief Node writing rule
639    ///
640    /// Add a node writing rule to the writer.
[127]641    DigraphWriter& node(const std::string& caption, const Node& node) {
642      typedef _writer_bits::MapLookUpConverter<Node> Converter;
643      Converter converter(_node_index);
[209]644      _writer_bits::ValueStorageBase* storage =
645        new _writer_bits::ValueStorage<Node, Converter>(node, converter);
[127]646      _attributes.push_back(std::make_pair(caption, storage));
647      return *this;
648    }
649
[156]650    /// \brief Arc writing rule
651    ///
652    /// Add an arc writing rule to writer.
[127]653    DigraphWriter& arc(const std::string& caption, const Arc& arc) {
654      typedef _writer_bits::MapLookUpConverter<Arc> Converter;
655      Converter converter(_arc_index);
[209]656      _writer_bits::ValueStorageBase* storage =
657        new _writer_bits::ValueStorage<Arc, Converter>(arc, converter);
[127]658      _attributes.push_back(std::make_pair(caption, storage));
659      return *this;
660    }
661
[192]662    /// \name Section captions
[156]663    /// @{
664
[192]665    /// \brief Add an additional caption to the \c \@nodes section
[156]666    ///
[192]667    /// Add an additional caption to the \c \@nodes section.
[127]668    DigraphWriter& nodes(const std::string& caption) {
669      _nodes_caption = caption;
670      return *this;
671    }
672
[192]673    /// \brief Add an additional caption to the \c \@arcs section
[156]674    ///
[192]675    /// Add an additional caption to the \c \@arcs section.
[127]676    DigraphWriter& arcs(const std::string& caption) {
677      _arcs_caption = caption;
678      return *this;
679    }
680
[192]681    /// \brief Add an additional caption to the \c \@attributes section
[156]682    ///
[192]683    /// Add an additional caption to the \c \@attributes section.
[127]684    DigraphWriter& attributes(const std::string& caption) {
685      _attributes_caption = caption;
686      return *this;
687    }
688
[156]689    /// \name Skipping section
690    /// @{
691
692    /// \brief Skip writing the node set
693    ///
[192]694    /// The \c \@nodes section will not be written to the stream.
[127]695    DigraphWriter& skipNodes() {
696      LEMON_ASSERT(!_skip_nodes, "Multiple usage of skipNodes() member");
[185]697      _skip_nodes = true;
[127]698      return *this;
699    }
700
[156]701    /// \brief Skip writing arc set
702    ///
[192]703    /// The \c \@arcs section will not be written to the stream.
[127]704    DigraphWriter& skipArcs() {
705      LEMON_ASSERT(!_skip_arcs, "Multiple usage of skipArcs() member");
[185]706      _skip_arcs = true;
[127]707      return *this;
708    }
709
[156]710    /// @}
711
[127]712  private:
713
714    void writeNodes() {
715      _writer_bits::MapStorageBase<Node>* label = 0;
716      for (typename NodeMaps::iterator it = _node_maps.begin();
[209]717           it != _node_maps.end(); ++it) {
[127]718        if (it->first == "label") {
[209]719          label = it->second;
720          break;
721        }
[127]722      }
723
724      *_os << "@nodes";
725      if (!_nodes_caption.empty()) {
[209]726        _writer_bits::writeToken(*_os << ' ', _nodes_caption);
[127]727      }
728      *_os << std::endl;
729
730      if (label == 0) {
[209]731        *_os << "label" << '\t';
[127]732      }
733      for (typename NodeMaps::iterator it = _node_maps.begin();
[209]734           it != _node_maps.end(); ++it) {
735        _writer_bits::writeToken(*_os, it->first) << '\t';
[127]736      }
737      *_os << std::endl;
738
739      std::vector<Node> nodes;
740      for (NodeIt n(_digraph); n != INVALID; ++n) {
[209]741        nodes.push_back(n);
[127]742      }
[209]743
[127]744      if (label == 0) {
[209]745        IdMap<Digraph, Node> id_map(_digraph);
746        _writer_bits::MapLess<IdMap<Digraph, Node> > id_less(id_map);
747        std::sort(nodes.begin(), nodes.end(), id_less);
[127]748      } else {
[209]749        label->sort(nodes);
[127]750      }
751
752      for (int i = 0; i < static_cast<int>(nodes.size()); ++i) {
[209]753        Node n = nodes[i];
754        if (label == 0) {
755          std::ostringstream os;
756          os << _digraph.id(n);
757          _writer_bits::writeToken(*_os, os.str());
758          *_os << '\t';
759          _node_index.insert(std::make_pair(n, os.str()));
760        }
761        for (typename NodeMaps::iterator it = _node_maps.begin();
762             it != _node_maps.end(); ++it) {
763          std::string value = it->second->get(n);
764          _writer_bits::writeToken(*_os, value);
765          if (it->first == "label") {
766            _node_index.insert(std::make_pair(n, value));
767          }
768          *_os << '\t';
769        }
770        *_os << std::endl;
[127]771      }
772    }
773
[185]774    void createNodeIndex() {
775      _writer_bits::MapStorageBase<Node>* label = 0;
776      for (typename NodeMaps::iterator it = _node_maps.begin();
[209]777           it != _node_maps.end(); ++it) {
[185]778        if (it->first == "label") {
[209]779          label = it->second;
780          break;
781        }
[185]782      }
783
784      if (label == 0) {
[209]785        for (NodeIt n(_digraph); n != INVALID; ++n) {
786          std::ostringstream os;
787          os << _digraph.id(n);
788          _node_index.insert(std::make_pair(n, os.str()));
789        }
[185]790      } else {
[209]791        for (NodeIt n(_digraph); n != INVALID; ++n) {
792          std::string value = label->get(n);
793          _node_index.insert(std::make_pair(n, value));
794        }
[185]795      }
796    }
797
[127]798    void writeArcs() {
799      _writer_bits::MapStorageBase<Arc>* label = 0;
800      for (typename ArcMaps::iterator it = _arc_maps.begin();
[209]801           it != _arc_maps.end(); ++it) {
[127]802        if (it->first == "label") {
[209]803          label = it->second;
804          break;
805        }
[127]806      }
807
808      *_os << "@arcs";
809      if (!_arcs_caption.empty()) {
[209]810        _writer_bits::writeToken(*_os << ' ', _arcs_caption);
[127]811      }
812      *_os << std::endl;
813
814      *_os << '\t' << '\t';
815      if (label == 0) {
[209]816        *_os << "label" << '\t';
[127]817      }
818      for (typename ArcMaps::iterator it = _arc_maps.begin();
[209]819           it != _arc_maps.end(); ++it) {
820        _writer_bits::writeToken(*_os, it->first) << '\t';
[127]821      }
822      *_os << std::endl;
823
824      std::vector<Arc> arcs;
825      for (ArcIt n(_digraph); n != INVALID; ++n) {
[209]826        arcs.push_back(n);
[127]827      }
[209]828
[127]829      if (label == 0) {
[209]830        IdMap<Digraph, Arc> id_map(_digraph);
831        _writer_bits::MapLess<IdMap<Digraph, Arc> > id_less(id_map);
832        std::sort(arcs.begin(), arcs.end(), id_less);
[127]833      } else {
[209]834        label->sort(arcs);
[127]835      }
836
837      for (int i = 0; i < static_cast<int>(arcs.size()); ++i) {
[209]838        Arc a = arcs[i];
839        _writer_bits::writeToken(*_os, _node_index.
840                                 find(_digraph.source(a))->second);
841        *_os << '\t';
842        _writer_bits::writeToken(*_os, _node_index.
843                                 find(_digraph.target(a))->second);
844        *_os << '\t';
845        if (label == 0) {
846          std::ostringstream os;
847          os << _digraph.id(a);
848          _writer_bits::writeToken(*_os, os.str());
849          *_os << '\t';
850          _arc_index.insert(std::make_pair(a, os.str()));
851        }
852        for (typename ArcMaps::iterator it = _arc_maps.begin();
853             it != _arc_maps.end(); ++it) {
854          std::string value = it->second->get(a);
855          _writer_bits::writeToken(*_os, value);
856          if (it->first == "label") {
857            _arc_index.insert(std::make_pair(a, value));
858          }
859          *_os << '\t';
860        }
861        *_os << std::endl;
[127]862      }
863    }
864
[185]865    void createArcIndex() {
866      _writer_bits::MapStorageBase<Arc>* label = 0;
867      for (typename ArcMaps::iterator it = _arc_maps.begin();
[209]868           it != _arc_maps.end(); ++it) {
[185]869        if (it->first == "label") {
[209]870          label = it->second;
871          break;
872        }
[185]873      }
874
875      if (label == 0) {
[209]876        for (ArcIt a(_digraph); a != INVALID; ++a) {
877          std::ostringstream os;
878          os << _digraph.id(a);
879          _arc_index.insert(std::make_pair(a, os.str()));
880        }
[185]881      } else {
[209]882        for (ArcIt a(_digraph); a != INVALID; ++a) {
883          std::string value = label->get(a);
884          _arc_index.insert(std::make_pair(a, value));
885        }
[185]886      }
887    }
888
[127]889    void writeAttributes() {
890      if (_attributes.empty()) return;
891      *_os << "@attributes";
892      if (!_attributes_caption.empty()) {
[209]893        _writer_bits::writeToken(*_os << ' ', _attributes_caption);
[127]894      }
895      *_os << std::endl;
896      for (typename Attributes::iterator it = _attributes.begin();
[209]897           it != _attributes.end(); ++it) {
898        _writer_bits::writeToken(*_os, it->first) << ' ';
899        _writer_bits::writeToken(*_os, it->second->get());
900        *_os << std::endl;
[127]901      }
902    }
[209]903
[127]904  public:
[209]905
906    /// \name Execution of the writer
[156]907    /// @{
908
909    /// \brief Start the batch processing
910    ///
[192]911    /// This function starts the batch processing.
[127]912    void run() {
913      if (!_skip_nodes) {
[209]914        writeNodes();
[185]915      } else {
[209]916        createNodeIndex();
[127]917      }
[209]918      if (!_skip_arcs) {
919        writeArcs();
[185]920      } else {
[209]921        createArcIndex();
[127]922      }
923      writeAttributes();
924    }
925
[192]926    /// \brief Give back the stream of the writer
[156]927    ///
[192]928    /// Give back the stream of the writer.
[156]929    std::ostream& ostream() {
[127]930      return *_os;
931    }
[156]932
933    /// @}
[127]934  };
935
[303]936  template <typename Graph>
937  class GraphWriter;
938
939  /// \brief Return a \ref GraphWriter class
[209]940  ///
[303]941  /// This function just returns a \ref GraphWriter class.
942  /// \relates GraphWriter
943  template <typename Graph>
944  GraphWriter<Graph> graphWriter(const Graph& graph,
945                                 std::ostream& os = std::cout) {
946    GraphWriter<Graph> tmp(graph, os);
[163]947    return tmp;
[127]948  }
949
[303]950  /// \brief Return a \ref GraphWriter class
[209]951  ///
[303]952  /// This function just returns a \ref GraphWriter class.
953  /// \relates GraphWriter
954  template <typename Graph>
955  GraphWriter<Graph> graphWriter(const Graph& graph, const std::string& fn) {
956    GraphWriter<Graph> tmp(graph, fn);
[163]957    return tmp;
[127]958  }
959
[303]960  /// \brief Return a \ref GraphWriter class
[209]961  ///
[303]962  /// This function just returns a \ref GraphWriter class.
963  /// \relates GraphWriter
964  template <typename Graph>
965  GraphWriter<Graph> graphWriter(const Graph& graph, const char* fn) {
966    GraphWriter<Graph> tmp(graph, fn);
[163]967    return tmp;
[127]968  }
[165]969
970  /// \ingroup lemon_io
[209]971  ///
[192]972  /// \brief \ref lgf-format "LGF" writer for directed graphs
[165]973  ///
974  /// This utility writes an \ref lgf-format "LGF" file.
[192]975  ///
976  /// It can be used almost the same way as \c DigraphWriter.
977  /// The only difference is that this class can handle edges and
978  /// edge maps as well as arcs and arc maps.
[201]979  ///
980  /// The arc maps are written into the file as two columns, the
981  /// caption of the columns are the name of the map prefixed with \c
982  /// '+' and \c '-'. The arcs are written into the \c \@attributes
983  /// section as a \c '+' or a \c '-' prefix (depends on the direction
984  /// of the arc) and the label of corresponding edge.
[165]985  template <typename _Graph>
986  class GraphWriter {
987  public:
988
989    typedef _Graph Graph;
990    TEMPLATE_GRAPH_TYPEDEFS(Graph);
[209]991
[165]992  private:
993
994
995    std::ostream* _os;
996    bool local_os;
997
[237]998    const Graph& _graph;
[165]999
1000    std::string _nodes_caption;
1001    std::string _edges_caption;
1002    std::string _attributes_caption;
[209]1003
[165]1004    typedef std::map<Node, std::string> NodeIndex;
1005    NodeIndex _node_index;
1006    typedef std::map<Edge, std::string> EdgeIndex;
1007    EdgeIndex _edge_index;
1008
[209]1009    typedef std::vector<std::pair<std::string,
1010      _writer_bits::MapStorageBase<Node>* > > NodeMaps;
1011    NodeMaps _node_maps;
[165]1012
[209]1013    typedef std::vector<std::pair<std::string,
[165]1014      _writer_bits::MapStorageBase<Edge>* > >EdgeMaps;
1015    EdgeMaps _edge_maps;
1016
[209]1017    typedef std::vector<std::pair<std::string,
[165]1018      _writer_bits::ValueStorageBase*> > Attributes;
1019    Attributes _attributes;
1020
1021    bool _skip_nodes;
1022    bool _skip_edges;
1023
1024  public:
1025
1026    /// \brief Constructor
1027    ///
1028    /// Construct a directed graph writer, which writes to the given
1029    /// output stream.
[293]1030    GraphWriter(const Graph& graph, std::ostream& os = std::cout)
1031      : _os(&os), local_os(false), _graph(graph),
[209]1032        _skip_nodes(false), _skip_edges(false) {}
[165]1033
1034    /// \brief Constructor
1035    ///
1036    /// Construct a directed graph writer, which writes to the given
1037    /// output file.
[293]1038    GraphWriter(const Graph& graph, const std::string& fn)
[165]1039      : _os(new std::ofstream(fn.c_str())), local_os(true), _graph(graph),
[290]1040        _skip_nodes(false), _skip_edges(false) {
[295]1041      if (!(*_os)) {
1042        delete _os;
1043        throw IoError("Cannot write file", fn);
1044      }
[290]1045    }
[165]1046
1047    /// \brief Constructor
1048    ///
1049    /// Construct a directed graph writer, which writes to the given
1050    /// output file.
[293]1051    GraphWriter(const Graph& graph, const char* fn)
[165]1052      : _os(new std::ofstream(fn)), local_os(true), _graph(graph),
[290]1053        _skip_nodes(false), _skip_edges(false) {
[295]1054      if (!(*_os)) {
1055        delete _os;
1056        throw IoError("Cannot write file", fn);
1057      }
[290]1058    }
[165]1059
1060    /// \brief Destructor
1061    ~GraphWriter() {
[209]1062      for (typename NodeMaps::iterator it = _node_maps.begin();
1063           it != _node_maps.end(); ++it) {
1064        delete it->second;
[165]1065      }
1066
[209]1067      for (typename EdgeMaps::iterator it = _edge_maps.begin();
1068           it != _edge_maps.end(); ++it) {
1069        delete it->second;
[165]1070      }
1071
[209]1072      for (typename Attributes::iterator it = _attributes.begin();
1073           it != _attributes.end(); ++it) {
1074        delete it->second;
[165]1075      }
1076
1077      if (local_os) {
[209]1078        delete _os;
[165]1079      }
1080    }
[209]1081
[190]1082  private:
[165]1083
[293]1084    friend GraphWriter<Graph> graphWriter<>(const Graph& graph,
1085                                            std::ostream& os);
1086    friend GraphWriter<Graph> graphWriter<>(const Graph& graph,
1087                                            const std::string& fn);
1088    friend GraphWriter<Graph> graphWriter<>(const Graph& graph,
1089                                            const char *fn);
[190]1090
[209]1091    GraphWriter(GraphWriter& other)
[190]1092      : _os(other._os), local_os(other.local_os), _graph(other._graph),
[209]1093        _skip_nodes(other._skip_nodes), _skip_edges(other._skip_edges) {
[190]1094
1095      other._os = 0;
1096      other.local_os = false;
1097
1098      _node_index.swap(other._node_index);
1099      _edge_index.swap(other._edge_index);
1100
1101      _node_maps.swap(other._node_maps);
1102      _edge_maps.swap(other._edge_maps);
1103      _attributes.swap(other._attributes);
1104
1105      _nodes_caption = other._nodes_caption;
1106      _edges_caption = other._edges_caption;
1107      _attributes_caption = other._attributes_caption;
1108    }
1109
[165]1110    GraphWriter& operator=(const GraphWriter&);
1111
1112  public:
1113
1114    /// \name Writing rules
1115    /// @{
[209]1116
[192]1117    /// \brief Node map writing rule
[165]1118    ///
[192]1119    /// Add a node map writing rule to the writer.
[165]1120    template <typename Map>
1121    GraphWriter& nodeMap(const std::string& caption, const Map& map) {
1122      checkConcept<concepts::ReadMap<Node, typename Map::Value>, Map>();
[209]1123      _writer_bits::MapStorageBase<Node>* storage =
1124        new _writer_bits::MapStorage<Node, Map>(map);
[165]1125      _node_maps.push_back(std::make_pair(caption, storage));
1126      return *this;
1127    }
1128
1129    /// \brief Node map writing rule
1130    ///
1131    /// Add a node map writing rule with specialized converter to the
1132    /// writer.
1133    template <typename Map, typename Converter>
[209]1134    GraphWriter& nodeMap(const std::string& caption, const Map& map,
1135                           const Converter& converter = Converter()) {
[165]1136      checkConcept<concepts::ReadMap<Node, typename Map::Value>, Map>();
[209]1137      _writer_bits::MapStorageBase<Node>* storage =
1138        new _writer_bits::MapStorage<Node, Map, Converter>(map, converter);
[165]1139      _node_maps.push_back(std::make_pair(caption, storage));
1140      return *this;
1141    }
1142
1143    /// \brief Edge map writing rule
1144    ///
1145    /// Add an edge map writing rule to the writer.
1146    template <typename Map>
1147    GraphWriter& edgeMap(const std::string& caption, const Map& map) {
1148      checkConcept<concepts::ReadMap<Edge, typename Map::Value>, Map>();
[209]1149      _writer_bits::MapStorageBase<Edge>* storage =
1150        new _writer_bits::MapStorage<Edge, Map>(map);
[165]1151      _edge_maps.push_back(std::make_pair(caption, storage));
1152      return *this;
1153    }
1154
1155    /// \brief Edge map writing rule
1156    ///
1157    /// Add an edge map writing rule with specialized converter to the
1158    /// writer.
1159    template <typename Map, typename Converter>
[209]1160    GraphWriter& edgeMap(const std::string& caption, const Map& map,
1161                          const Converter& converter = Converter()) {
[165]1162      checkConcept<concepts::ReadMap<Edge, typename Map::Value>, Map>();
[209]1163      _writer_bits::MapStorageBase<Edge>* storage =
1164        new _writer_bits::MapStorage<Edge, Map, Converter>(map, converter);
[165]1165      _edge_maps.push_back(std::make_pair(caption, storage));
1166      return *this;
1167    }
1168
1169    /// \brief Arc map writing rule
1170    ///
1171    /// Add an arc map writing rule to the writer.
1172    template <typename Map>
1173    GraphWriter& arcMap(const std::string& caption, const Map& map) {
1174      checkConcept<concepts::ReadMap<Arc, typename Map::Value>, Map>();
[209]1175      _writer_bits::MapStorageBase<Edge>* forward_storage =
1176        new _writer_bits::GraphArcMapStorage<Graph, true, Map>(_graph, map);
[165]1177      _edge_maps.push_back(std::make_pair('+' + caption, forward_storage));
[209]1178      _writer_bits::MapStorageBase<Edge>* backward_storage =
1179        new _writer_bits::GraphArcMapStorage<Graph, false, Map>(_graph, map);
[165]1180      _edge_maps.push_back(std::make_pair('-' + caption, backward_storage));
1181      return *this;
1182    }
1183
1184    /// \brief Arc map writing rule
1185    ///
1186    /// Add an arc map writing rule with specialized converter to the
1187    /// writer.
1188    template <typename Map, typename Converter>
[209]1189    GraphWriter& arcMap(const std::string& caption, const Map& map,
1190                          const Converter& converter = Converter()) {
[165]1191      checkConcept<concepts::ReadMap<Arc, typename Map::Value>, Map>();
[209]1192      _writer_bits::MapStorageBase<Edge>* forward_storage =
1193        new _writer_bits::GraphArcMapStorage<Graph, true, Map, Converter>
1194        (_graph, map, converter);
[165]1195      _edge_maps.push_back(std::make_pair('+' + caption, forward_storage));
[209]1196      _writer_bits::MapStorageBase<Edge>* backward_storage =
1197        new _writer_bits::GraphArcMapStorage<Graph, false, Map, Converter>
1198        (_graph, map, converter);
[165]1199      _edge_maps.push_back(std::make_pair('-' + caption, backward_storage));
1200      return *this;
1201    }
1202
1203    /// \brief Attribute writing rule
1204    ///
1205    /// Add an attribute writing rule to the writer.
1206    template <typename Value>
1207    GraphWriter& attribute(const std::string& caption, const Value& value) {
[209]1208      _writer_bits::ValueStorageBase* storage =
1209        new _writer_bits::ValueStorage<Value>(value);
[165]1210      _attributes.push_back(std::make_pair(caption, storage));
1211      return *this;
1212    }
1213
1214    /// \brief Attribute writing rule
1215    ///
1216    /// Add an attribute writing rule with specialized converter to the
1217    /// writer.
1218    template <typename Value, typename Converter>
[209]1219    GraphWriter& attribute(const std::string& caption, const Value& value,
1220                             const Converter& converter = Converter()) {
1221      _writer_bits::ValueStorageBase* storage =
1222        new _writer_bits::ValueStorage<Value, Converter>(value, converter);
[165]1223      _attributes.push_back(std::make_pair(caption, storage));
1224      return *this;
1225    }
1226
1227    /// \brief Node writing rule
1228    ///
1229    /// Add a node writing rule to the writer.
1230    GraphWriter& node(const std::string& caption, const Node& node) {
1231      typedef _writer_bits::MapLookUpConverter<Node> Converter;
1232      Converter converter(_node_index);
[209]1233      _writer_bits::ValueStorageBase* storage =
1234        new _writer_bits::ValueStorage<Node, Converter>(node, converter);
[165]1235      _attributes.push_back(std::make_pair(caption, storage));
1236      return *this;
1237    }
1238
1239    /// \brief Edge writing rule
1240    ///
1241    /// Add an edge writing rule to writer.
1242    GraphWriter& edge(const std::string& caption, const Edge& edge) {
1243      typedef _writer_bits::MapLookUpConverter<Edge> Converter;
1244      Converter converter(_edge_index);
[209]1245      _writer_bits::ValueStorageBase* storage =
1246        new _writer_bits::ValueStorage<Edge, Converter>(edge, converter);
[165]1247      _attributes.push_back(std::make_pair(caption, storage));
1248      return *this;
1249    }
1250
1251    /// \brief Arc writing rule
1252    ///
1253    /// Add an arc writing rule to writer.
1254    GraphWriter& arc(const std::string& caption, const Arc& arc) {
1255      typedef _writer_bits::GraphArcLookUpConverter<Graph> Converter;
1256      Converter converter(_graph, _edge_index);
[209]1257      _writer_bits::ValueStorageBase* storage =
1258        new _writer_bits::ValueStorage<Arc, Converter>(arc, converter);
[165]1259      _attributes.push_back(std::make_pair(caption, storage));
1260      return *this;
1261    }
1262
[192]1263    /// \name Section captions
[165]1264    /// @{
1265
[192]1266    /// \brief Add an additional caption to the \c \@nodes section
[165]1267    ///
[192]1268    /// Add an additional caption to the \c \@nodes section.
[165]1269    GraphWriter& nodes(const std::string& caption) {
1270      _nodes_caption = caption;
1271      return *this;
1272    }
1273
[192]1274    /// \brief Add an additional caption to the \c \@arcs section
[165]1275    ///
[192]1276    /// Add an additional caption to the \c \@arcs section.
[165]1277    GraphWriter& edges(const std::string& caption) {
1278      _edges_caption = caption;
1279      return *this;
1280    }
1281
[192]1282    /// \brief Add an additional caption to the \c \@attributes section
[165]1283    ///
[192]1284    /// Add an additional caption to the \c \@attributes section.
[165]1285    GraphWriter& attributes(const std::string& caption) {
1286      _attributes_caption = caption;
1287      return *this;
1288    }
1289
1290    /// \name Skipping section
1291    /// @{
1292
1293    /// \brief Skip writing the node set
1294    ///
[192]1295    /// The \c \@nodes section will not be written to the stream.
[165]1296    GraphWriter& skipNodes() {
1297      LEMON_ASSERT(!_skip_nodes, "Multiple usage of skipNodes() member");
[185]1298      _skip_nodes = true;
[165]1299      return *this;
1300    }
1301
1302    /// \brief Skip writing edge set
1303    ///
[192]1304    /// The \c \@edges section will not be written to the stream.
[165]1305    GraphWriter& skipEdges() {
1306      LEMON_ASSERT(!_skip_edges, "Multiple usage of skipEdges() member");
[185]1307      _skip_edges = true;
[165]1308      return *this;
1309    }
1310
1311    /// @}
1312
1313  private:
1314
1315    void writeNodes() {
1316      _writer_bits::MapStorageBase<Node>* label = 0;
1317      for (typename NodeMaps::iterator it = _node_maps.begin();
[209]1318           it != _node_maps.end(); ++it) {
[165]1319        if (it->first == "label") {
[209]1320          label = it->second;
1321          break;
1322        }
[165]1323      }
1324
1325      *_os << "@nodes";
1326      if (!_nodes_caption.empty()) {
[209]1327        _writer_bits::writeToken(*_os << ' ', _nodes_caption);
[165]1328      }
1329      *_os << std::endl;
1330
1331      if (label == 0) {
[209]1332        *_os << "label" << '\t';
[165]1333      }
1334      for (typename NodeMaps::iterator it = _node_maps.begin();
[209]1335           it != _node_maps.end(); ++it) {
1336        _writer_bits::writeToken(*_os, it->first) << '\t';
[165]1337      }
1338      *_os << std::endl;
1339
1340      std::vector<Node> nodes;
1341      for (NodeIt n(_graph); n != INVALID; ++n) {
[209]1342        nodes.push_back(n);
[165]1343      }
[209]1344
[165]1345      if (label == 0) {
[209]1346        IdMap<Graph, Node> id_map(_graph);
1347        _writer_bits::MapLess<IdMap<Graph, Node> > id_less(id_map);
1348        std::sort(nodes.begin(), nodes.end(), id_less);
[165]1349      } else {
[209]1350        label->sort(nodes);
[165]1351      }
1352
1353      for (int i = 0; i < static_cast<int>(nodes.size()); ++i) {
[209]1354        Node n = nodes[i];
1355        if (label == 0) {
1356          std::ostringstream os;
1357          os << _graph.id(n);
1358          _writer_bits::writeToken(*_os, os.str());
1359          *_os << '\t';
1360          _node_index.insert(std::make_pair(n, os.str()));
1361        }
1362        for (typename NodeMaps::iterator it = _node_maps.begin();
1363             it != _node_maps.end(); ++it) {
1364          std::string value = it->second->get(n);
1365          _writer_bits::writeToken(*_os, value);
1366          if (it->first == "label") {
1367            _node_index.insert(std::make_pair(n, value));
1368          }
1369          *_os << '\t';
1370        }
1371        *_os << std::endl;
[165]1372      }
1373    }
1374
[185]1375    void createNodeIndex() {
1376      _writer_bits::MapStorageBase<Node>* label = 0;
1377      for (typename NodeMaps::iterator it = _node_maps.begin();
[209]1378           it != _node_maps.end(); ++it) {
[185]1379        if (it->first == "label") {
[209]1380          label = it->second;
1381          break;
1382        }
[185]1383      }
1384
1385      if (label == 0) {
[209]1386        for (NodeIt n(_graph); n != INVALID; ++n) {
1387          std::ostringstream os;
1388          os << _graph.id(n);
1389          _node_index.insert(std::make_pair(n, os.str()));
1390        }
[185]1391      } else {
[209]1392        for (NodeIt n(_graph); n != INVALID; ++n) {
1393          std::string value = label->get(n);
1394          _node_index.insert(std::make_pair(n, value));
1395        }
[185]1396      }
1397    }
1398
[165]1399    void writeEdges() {
1400      _writer_bits::MapStorageBase<Edge>* label = 0;
1401      for (typename EdgeMaps::iterator it = _edge_maps.begin();
[209]1402           it != _edge_maps.end(); ++it) {
[165]1403        if (it->first == "label") {
[209]1404          label = it->second;
1405          break;
1406        }
[165]1407      }
1408
1409      *_os << "@edges";
1410      if (!_edges_caption.empty()) {
[209]1411        _writer_bits::writeToken(*_os << ' ', _edges_caption);
[165]1412      }
1413      *_os << std::endl;
1414
1415      *_os << '\t' << '\t';
1416      if (label == 0) {
[209]1417        *_os << "label" << '\t';
[165]1418      }
1419      for (typename EdgeMaps::iterator it = _edge_maps.begin();
[209]1420           it != _edge_maps.end(); ++it) {
1421        _writer_bits::writeToken(*_os, it->first) << '\t';
[165]1422      }
1423      *_os << std::endl;
1424
1425      std::vector<Edge> edges;
1426      for (EdgeIt n(_graph); n != INVALID; ++n) {
[209]1427        edges.push_back(n);
[165]1428      }
[209]1429
[165]1430      if (label == 0) {
[209]1431        IdMap<Graph, Edge> id_map(_graph);
1432        _writer_bits::MapLess<IdMap<Graph, Edge> > id_less(id_map);
1433        std::sort(edges.begin(), edges.end(), id_less);
[165]1434      } else {
[209]1435        label->sort(edges);
[165]1436      }
1437
1438      for (int i = 0; i < static_cast<int>(edges.size()); ++i) {
[209]1439        Edge e = edges[i];
1440        _writer_bits::writeToken(*_os, _node_index.
1441                                 find(_graph.u(e))->second);
1442        *_os << '\t';
1443        _writer_bits::writeToken(*_os, _node_index.
1444                                 find(_graph.v(e))->second);
1445        *_os << '\t';
1446        if (label == 0) {
1447          std::ostringstream os;
1448          os << _graph.id(e);
1449          _writer_bits::writeToken(*_os, os.str());
1450          *_os << '\t';
1451          _edge_index.insert(std::make_pair(e, os.str()));
1452        }
1453        for (typename EdgeMaps::iterator it = _edge_maps.begin();
1454             it != _edge_maps.end(); ++it) {
1455          std::string value = it->second->get(e);
1456          _writer_bits::writeToken(*_os, value);
1457          if (it->first == "label") {
1458            _edge_index.insert(std::make_pair(e, value));
1459          }
1460          *_os << '\t';
1461        }
1462        *_os << std::endl;
[165]1463      }
1464    }
1465
[185]1466    void createEdgeIndex() {
1467      _writer_bits::MapStorageBase<Edge>* label = 0;
1468      for (typename EdgeMaps::iterator it = _edge_maps.begin();
[209]1469           it != _edge_maps.end(); ++it) {
[185]1470        if (it->first == "label") {
[209]1471          label = it->second;
1472          break;
1473        }
[185]1474      }
1475
1476      if (label == 0) {
[209]1477        for (EdgeIt e(_graph); e != INVALID; ++e) {
1478          std::ostringstream os;
1479          os << _graph.id(e);
1480          _edge_index.insert(std::make_pair(e, os.str()));
1481        }
[185]1482      } else {
[209]1483        for (EdgeIt e(_graph); e != INVALID; ++e) {
1484          std::string value = label->get(e);
1485          _edge_index.insert(std::make_pair(e, value));
1486        }
[185]1487      }
1488    }
1489
[165]1490    void writeAttributes() {
1491      if (_attributes.empty()) return;
1492      *_os << "@attributes";
1493      if (!_attributes_caption.empty()) {
[209]1494        _writer_bits::writeToken(*_os << ' ', _attributes_caption);
[165]1495      }
1496      *_os << std::endl;
1497      for (typename Attributes::iterator it = _attributes.begin();
[209]1498           it != _attributes.end(); ++it) {
1499        _writer_bits::writeToken(*_os, it->first) << ' ';
1500        _writer_bits::writeToken(*_os, it->second->get());
1501        *_os << std::endl;
[165]1502      }
1503    }
[209]1504
[165]1505  public:
[209]1506
1507    /// \name Execution of the writer
[165]1508    /// @{
1509
1510    /// \brief Start the batch processing
1511    ///
[192]1512    /// This function starts the batch processing.
[165]1513    void run() {
1514      if (!_skip_nodes) {
[209]1515        writeNodes();
[185]1516      } else {
[209]1517        createNodeIndex();
[165]1518      }
[209]1519      if (!_skip_edges) {
1520        writeEdges();
[185]1521      } else {
[209]1522        createEdgeIndex();
[165]1523      }
1524      writeAttributes();
1525    }
1526
[192]1527    /// \brief Give back the stream of the writer
[165]1528    ///
[192]1529    /// Give back the stream of the writer
[165]1530    std::ostream& ostream() {
1531      return *_os;
1532    }
1533
1534    /// @}
1535  };
1536
[248]1537  class SectionWriter;
1538
1539  SectionWriter sectionWriter(std::istream& is);
1540  SectionWriter sectionWriter(const std::string& fn);
1541  SectionWriter sectionWriter(const char* fn);
1542
1543  /// \ingroup lemon_io
1544  ///
1545  /// \brief Section writer class
1546  ///
1547  /// In the \ref lgf-format "LGF" file extra sections can be placed,
1548  /// which contain any data in arbitrary format. Such sections can be
1549  /// written with this class. A writing rule can be added to the
1550  /// class with two different functions. With the \c sectionLines()
1551  /// function a generator can write the section line-by-line, while
1552  /// with the \c sectionStream() member the section can be written to
1553  /// an output stream.
1554  class SectionWriter {
1555  private:
1556
1557    std::ostream* _os;
1558    bool local_os;
1559
1560    typedef std::vector<std::pair<std::string, _writer_bits::Section*> >
1561    Sections;
1562
1563    Sections _sections;
1564
1565  public:
1566
1567    /// \brief Constructor
1568    ///
1569    /// Construct a section writer, which writes to the given output
1570    /// stream.
1571    SectionWriter(std::ostream& os)
1572      : _os(&os), local_os(false) {}
1573
1574    /// \brief Constructor
1575    ///
1576    /// Construct a section writer, which writes into the given file.
1577    SectionWriter(const std::string& fn)
[290]1578      : _os(new std::ofstream(fn.c_str())), local_os(true) {
[295]1579      if (!(*_os)) {
1580        delete _os;
1581        throw IoError("Cannot write file", fn);
1582      }
[290]1583    }
[248]1584
1585    /// \brief Constructor
1586    ///
1587    /// Construct a section writer, which writes into the given file.
1588    SectionWriter(const char* fn)
[290]1589      : _os(new std::ofstream(fn)), local_os(true) {
[295]1590      if (!(*_os)) {
1591        delete _os;
1592        throw IoError("Cannot write file", fn);
1593      }
[290]1594    }
[248]1595
1596    /// \brief Destructor
1597    ~SectionWriter() {
1598      for (Sections::iterator it = _sections.begin();
1599           it != _sections.end(); ++it) {
1600        delete it->second;
1601      }
1602
1603      if (local_os) {
1604        delete _os;
1605      }
1606
1607    }
1608
1609  private:
1610
1611    friend SectionWriter sectionWriter(std::ostream& os);
1612    friend SectionWriter sectionWriter(const std::string& fn);
1613    friend SectionWriter sectionWriter(const char* fn);
1614
1615    SectionWriter(SectionWriter& other)
1616      : _os(other._os), local_os(other.local_os) {
1617
1618      other._os = 0;
1619      other.local_os = false;
1620
1621      _sections.swap(other._sections);
1622    }
1623
1624    SectionWriter& operator=(const SectionWriter&);
1625
1626  public:
1627
1628    /// \name Section writers
1629    /// @{
1630
1631    /// \brief Add a section writer with line oriented writing
1632    ///
1633    /// The first parameter is the type descriptor of the section, the
1634    /// second is a generator with std::string values. At the writing
1635    /// process, the returned \c std::string will be written into the
1636    /// output file until it is an empty string.
1637    ///
1638    /// For example, an integer vector is written into a section.
1639    ///\code
1640    ///  @numbers
1641    ///  12 45 23 78
1642    ///  4 28 38 28
1643    ///  23 6 16
1644    ///\endcode
1645    ///
1646    /// The generator is implemented as a struct.
1647    ///\code
1648    ///  struct NumberSection {
1649    ///    std::vector<int>::const_iterator _it, _end;
1650    ///    NumberSection(const std::vector<int>& data)
1651    ///      : _it(data.begin()), _end(data.end()) {}
1652    ///    std::string operator()() {
1653    ///      int rem_in_line = 4;
1654    ///      std::ostringstream ls;
1655    ///      while (rem_in_line > 0 && _it != _end) {
1656    ///        ls << *(_it++) << ' ';
1657    ///        --rem_in_line;
1658    ///      }
1659    ///      return ls.str();
1660    ///    }
1661    ///  };
1662    ///
1663    ///  // ...
1664    ///
1665    ///  writer.sectionLines("numbers", NumberSection(vec));
1666    ///\endcode
1667    template <typename Functor>
1668    SectionWriter& sectionLines(const std::string& type, Functor functor) {
1669      LEMON_ASSERT(!type.empty(), "Type is empty.");
1670      _sections.push_back(std::make_pair(type,
1671        new _writer_bits::LineSection<Functor>(functor)));
1672      return *this;
1673    }
1674
1675
1676    /// \brief Add a section writer with stream oriented writing
1677    ///
1678    /// The first parameter is the type of the section, the second is
1679    /// a functor, which takes a \c std::ostream& parameter. The
1680    /// functor writes the section to the output stream.
1681    /// \warning The last line must be closed with end-line character.
1682    template <typename Functor>
1683    SectionWriter& sectionStream(const std::string& type, Functor functor) {
1684      LEMON_ASSERT(!type.empty(), "Type is empty.");
1685      _sections.push_back(std::make_pair(type,
1686         new _writer_bits::StreamSection<Functor>(functor)));
1687      return *this;
1688    }
1689
1690    /// @}
1691
1692  public:
1693
1694
1695    /// \name Execution of the writer
1696    /// @{
1697
1698    /// \brief Start the batch processing
1699    ///
1700    /// This function starts the batch processing.
1701    void run() {
1702
1703      LEMON_ASSERT(_os != 0, "This writer is assigned to an other writer");
1704
1705      for (Sections::iterator it = _sections.begin();
1706           it != _sections.end(); ++it) {
1707        (*_os) << '@' << it->first << std::endl;
1708        it->second->process(*_os);
1709      }
1710    }
1711
1712    /// \brief Give back the stream of the writer
1713    ///
1714    /// Returns the stream of the writer
1715    std::ostream& ostream() {
1716      return *_os;
1717    }
1718
1719    /// @}
1720
1721  };
1722
1723  /// \brief Return a \ref SectionWriter class
1724  ///
1725  /// This function just returns a \ref SectionWriter class.
1726  /// \relates SectionWriter
1727  inline SectionWriter sectionWriter(std::ostream& os) {
1728    SectionWriter tmp(os);
1729    return tmp;
1730  }
1731
1732  /// \brief Return a \ref SectionWriter class
1733  ///
1734  /// This function just returns a \ref SectionWriter class.
1735  /// \relates SectionWriter
1736  inline SectionWriter sectionWriter(const std::string& fn) {
1737    SectionWriter tmp(fn);
1738    return tmp;
1739  }
1740
1741  /// \brief Return a \ref SectionWriter class
1742  ///
1743  /// This function just returns a \ref SectionWriter class.
1744  /// \relates SectionWriter
1745  inline SectionWriter sectionWriter(const char* fn) {
1746    SectionWriter tmp(fn);
1747    return tmp;
1748  }
[127]1749}
1750
1751#endif
Note: See TracBrowser for help on using the repository browser.