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