lemon/lgf_writer.h
author Balazs Dezso <deba@inf.elte.hu>
Tue, 30 Sep 2008 20:53:18 +0200
changeset 290 f6899946c1ac
parent 248 8fada33fc60a
child 291 d901321d6555
permissions -rw-r--r--
Simplifying exceptions

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