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