gravatar
deba@inf.elte.hu
deba@inf.elte.hu
Section writer class
0 1 0
default
1 file changed with 245 insertions and 0 deletions:
↑ Collapse diff ↑
Ignore white space 96 line context
1 1
/* -*- mode: C++; indent-tabs-mode: nil; -*-
2 2
 *
3 3
 * This file is a part of LEMON, a generic C++ optimization library.
4 4
 *
5 5
 * Copyright (C) 2003-2008
6 6
 * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
7 7
 * (Egervary Research Group on Combinatorial Optimization, EGRES).
8 8
 *
9 9
 * Permission to use, modify and distribute this software is granted
10 10
 * provided that this copyright notice appears in all copies. For
11 11
 * precise terms see the accompanying LICENSE file.
12 12
 *
13 13
 * This software is provided "AS IS" with no warranty of any kind,
14 14
 * express or implied, and with no claim as to its suitability for any
15 15
 * purpose.
16 16
 *
17 17
 */
18 18

	
19 19
///\ingroup lemon_io
20 20
///\file
21 21
///\brief \ref lgf-format "LEMON Graph Format" writer.
22 22

	
23 23

	
24 24
#ifndef LEMON_LGF_WRITER_H
25 25
#define LEMON_LGF_WRITER_H
26 26

	
27 27
#include <iostream>
28 28
#include <fstream>
29 29
#include <sstream>
30 30

	
31 31
#include <algorithm>
32 32

	
33 33
#include <vector>
34 34
#include <functional>
35 35

	
36 36
#include <lemon/assert.h>
37 37
#include <lemon/core.h>
38 38
#include <lemon/maps.h>
39 39

	
40
#include <lemon/concept_check.h>
41
#include <lemon/concepts/maps.h>
42

	
40 43
namespace lemon {
41 44

	
42 45
  namespace _writer_bits {
43 46

	
44 47
    template <typename Value>
45 48
    struct DefaultConverter {
46 49
      std::string operator()(const Value& value) {
47 50
        std::ostringstream os;
48 51
        os << value;
49 52
        return os.str();
50 53
      }
51 54
    };
52 55

	
53 56
    template <typename T>
54 57
    bool operator<(const T&, const T&) {
55 58
      throw DataFormatError("Label map is not comparable");
56 59
    }
57 60

	
58 61
    template <typename _Map>
59 62
    class MapLess {
60 63
    public:
61 64
      typedef _Map Map;
62 65
      typedef typename Map::Key Item;
63 66

	
64 67
    private:
65 68
      const Map& _map;
66 69

	
67 70
    public:
68 71
      MapLess(const Map& map) : _map(map) {}
69 72

	
70 73
      bool operator()(const Item& left, const Item& right) {
71 74
        return _map[left] < _map[right];
72 75
      }
73 76
    };
74 77

	
75 78
    template <typename _Graph, bool _dir, typename _Map>
76 79
    class GraphArcMapLess {
77 80
    public:
78 81
      typedef _Map Map;
79 82
      typedef _Graph Graph;
80 83
      typedef typename Graph::Edge Item;
81 84

	
82 85
    private:
83 86
      const Graph& _graph;
84 87
      const Map& _map;
85 88

	
86 89
    public:
87 90
      GraphArcMapLess(const Graph& graph, const Map& map)
... ...
@@ -259,96 +262,135 @@
259 262
      case '\n':
260 263
        os << "\\n";
261 264
        return;
262 265
      case '\t':
263 266
        os << "\\t";
264 267
        return;
265 268
      case '\v':
266 269
        os << "\\v";
267 270
        return;
268 271
      default:
269 272
        if (c < 0x20) {
270 273
          std::ios::fmtflags flags = os.flags();
271 274
          os << '\\' << std::oct << static_cast<int>(c);
272 275
          os.flags(flags);
273 276
        } else {
274 277
          os << c;
275 278
        }
276 279
        return;
277 280
      }
278 281
    }
279 282

	
280 283
    inline bool requireEscape(const std::string& str) {
281 284
      if (str.empty() || str[0] == '@') return true;
282 285
      std::istringstream is(str);
283 286
      char c;
284 287
      while (is.get(c)) {
285 288
        if (isWhiteSpace(c) || isEscaped(c)) {
286 289
          return true;
287 290
        }
288 291
      }
289 292
      return false;
290 293
    }
291 294

	
292 295
    inline std::ostream& writeToken(std::ostream& os, const std::string& str) {
293 296

	
294 297
      if (requireEscape(str)) {
295 298
        os << '\"';
296 299
        for (std::string::const_iterator it = str.begin();
297 300
             it != str.end(); ++it) {
298 301
          writeEscape(os, *it);
299 302
        }
300 303
        os << '\"';
301 304
      } else {
302 305
        os << str;
303 306
      }
304 307
      return os;
305 308
    }
306 309

	
310
    class Section {
311
    public:
312
      virtual ~Section() {}
313
      virtual void process(std::ostream& os) = 0;
314
    };
315

	
316
    template <typename Functor>
317
    class LineSection : public Section {
318
    private:
319

	
320
      Functor _functor;
321

	
322
    public:
323

	
324
      LineSection(const Functor& functor) : _functor(functor) {}
325
      virtual ~LineSection() {}
326

	
327
      virtual void process(std::ostream& os) {
328
        std::string line;
329
        while (!(line = _functor()).empty()) os << line << std::endl;
330
      }
331
    };
332

	
333
    template <typename Functor>
334
    class StreamSection : public Section {
335
    private:
336

	
337
      Functor _functor;
338

	
339
    public:
340

	
341
      StreamSection(const Functor& functor) : _functor(functor) {}
342
      virtual ~StreamSection() {}
343

	
344
      virtual void process(std::ostream& os) {
345
        _functor(os);
346
      }
347
    };
348

	
307 349
  }
308 350

	
309 351
  template <typename Digraph>
310 352
  class DigraphWriter;
311 353

	
312 354
  template <typename Digraph>
313 355
  DigraphWriter<Digraph> digraphWriter(std::ostream& os,
314 356
                                       const Digraph& digraph);
315 357

	
316 358
  template <typename Digraph>
317 359
  DigraphWriter<Digraph> digraphWriter(const std::string& fn,
318 360
                                       const Digraph& digraph);
319 361

	
320 362
  template <typename Digraph>
321 363
  DigraphWriter<Digraph> digraphWriter(const char *fn,
322 364
                                       const Digraph& digraph);
323 365

	
324 366
  /// \ingroup lemon_io
325 367
  ///
326 368
  /// \brief \ref lgf-format "LGF" writer for directed graphs
327 369
  ///
328 370
  /// This utility writes an \ref lgf-format "LGF" file.
329 371
  ///
330 372
  /// The writing method does a batch processing. The user creates a
331 373
  /// writer object, then various writing rules can be added to the
332 374
  /// writer, and eventually the writing is executed with the \c run()
333 375
  /// member function. A map writing rule can be added to the writer
334 376
  /// with the \c nodeMap() or \c arcMap() members. An optional
335 377
  /// converter parameter can also be added as a standard functor
336 378
  /// converting from the value type of the map to \c std::string. If it
337 379
  /// is set, it will determine how the value type of the map is written to
338 380
  /// the output stream. If the functor is not set, then a default
339 381
  /// conversion will be used. The \c attribute(), \c node() and \c
340 382
  /// arc() functions are used to add attribute writing rules.
341 383
  ///
342 384
  ///\code
343 385
  /// DigraphWriter<Digraph>(std::cout, digraph).
344 386
  ///   nodeMap("coordinates", coord_map).
345 387
  ///   nodeMap("size", size).
346 388
  ///   nodeMap("title", title).
347 389
  ///   arcMap("capacity", cap_map).
348 390
  ///   node("source", src).
349 391
  ///   node("target", trg).
350 392
  ///   attribute("caption", caption).
351 393
  ///   run();
352 394
  ///\endcode
353 395
  ///
354 396
  ///
... ...
@@ -1447,51 +1489,254 @@
1447 1489
      }
1448 1490
      if (!_skip_edges) {
1449 1491
        writeEdges();
1450 1492
      } else {
1451 1493
        createEdgeIndex();
1452 1494
      }
1453 1495
      writeAttributes();
1454 1496
    }
1455 1497

	
1456 1498
    /// \brief Give back the stream of the writer
1457 1499
    ///
1458 1500
    /// Give back the stream of the writer
1459 1501
    std::ostream& ostream() {
1460 1502
      return *_os;
1461 1503
    }
1462 1504

	
1463 1505
    /// @}
1464 1506
  };
1465 1507

	
1466 1508
  /// \brief Return a \ref GraphWriter class
1467 1509
  ///
1468 1510
  /// This function just returns a \ref GraphWriter class.
1469 1511
  /// \relates GraphWriter
1470 1512
  template <typename Graph>
1471 1513
  GraphWriter<Graph> graphWriter(std::ostream& os, const Graph& graph) {
1472 1514
    GraphWriter<Graph> tmp(os, graph);
1473 1515
    return tmp;
1474 1516
  }
1475 1517

	
1476 1518
  /// \brief Return a \ref GraphWriter class
1477 1519
  ///
1478 1520
  /// This function just returns a \ref GraphWriter class.
1479 1521
  /// \relates GraphWriter
1480 1522
  template <typename Graph>
1481 1523
  GraphWriter<Graph> graphWriter(const std::string& fn, const Graph& graph) {
1482 1524
    GraphWriter<Graph> tmp(fn, graph);
1483 1525
    return tmp;
1484 1526
  }
1485 1527

	
1486 1528
  /// \brief Return a \ref GraphWriter class
1487 1529
  ///
1488 1530
  /// This function just returns a \ref GraphWriter class.
1489 1531
  /// \relates GraphWriter
1490 1532
  template <typename Graph>
1491 1533
  GraphWriter<Graph> graphWriter(const char* fn, const Graph& graph) {
1492 1534
    GraphWriter<Graph> tmp(fn, graph);
1493 1535
    return tmp;
1494 1536
  }
1537

	
1538
  class SectionWriter;
1539

	
1540
  SectionWriter sectionWriter(std::istream& is);
1541
  SectionWriter sectionWriter(const std::string& fn);
1542
  SectionWriter sectionWriter(const char* fn);
1543

	
1544
  /// \ingroup lemon_io
1545
  ///
1546
  /// \brief Section writer class
1547
  ///
1548
  /// In the \ref lgf-format "LGF" file extra sections can be placed,
1549
  /// which contain any data in arbitrary format. Such sections can be
1550
  /// written with this class. A writing rule can be added to the
1551
  /// class with two different functions. With the \c sectionLines()
1552
  /// function a generator can write the section line-by-line, while
1553
  /// with the \c sectionStream() member the section can be written to
1554
  /// an output stream.
1555
  class SectionWriter {
1556
  private:
1557

	
1558
    std::ostream* _os;
1559
    bool local_os;
1560

	
1561
    typedef std::vector<std::pair<std::string, _writer_bits::Section*> >
1562
    Sections;
1563

	
1564
    Sections _sections;
1565

	
1566
  public:
1567

	
1568
    /// \brief Constructor
1569
    ///
1570
    /// Construct a section writer, which writes to the given output
1571
    /// stream.
1572
    SectionWriter(std::ostream& os)
1573
      : _os(&os), local_os(false) {}
1574

	
1575
    /// \brief Constructor
1576
    ///
1577
    /// Construct a section writer, which writes into the given file.
1578
    SectionWriter(const std::string& fn)
1579
      : _os(new std::ofstream(fn.c_str())), local_os(true) {}
1580

	
1581
    /// \brief Constructor
1582
    ///
1583
    /// Construct a section writer, which writes into the given file.
1584
    SectionWriter(const char* fn)
1585
      : _os(new std::ofstream(fn)), local_os(true) {}
1586

	
1587
    /// \brief Destructor
1588
    ~SectionWriter() {
1589
      for (Sections::iterator it = _sections.begin();
1590
           it != _sections.end(); ++it) {
1591
        delete it->second;
1592
      }
1593

	
1594
      if (local_os) {
1595
        delete _os;
1596
      }
1597

	
1598
    }
1599

	
1600
  private:
1601

	
1602
    friend SectionWriter sectionWriter(std::ostream& os);
1603
    friend SectionWriter sectionWriter(const std::string& fn);
1604
    friend SectionWriter sectionWriter(const char* fn);
1605

	
1606
    SectionWriter(SectionWriter& other)
1607
      : _os(other._os), local_os(other.local_os) {
1608

	
1609
      other._os = 0;
1610
      other.local_os = false;
1611

	
1612
      _sections.swap(other._sections);
1613
    }
1614

	
1615
    SectionWriter& operator=(const SectionWriter&);
1616

	
1617
  public:
1618

	
1619
    /// \name Section writers
1620
    /// @{
1621

	
1622
    /// \brief Add a section writer with line oriented writing
1623
    ///
1624
    /// The first parameter is the type descriptor of the section, the
1625
    /// second is a generator with std::string values. At the writing
1626
    /// process, the returned \c std::string will be written into the
1627
    /// output file until it is an empty string.
1628
    ///
1629
    /// For example, an integer vector is written into a section.
1630
    ///\code
1631
    ///  @numbers
1632
    ///  12 45 23 78
1633
    ///  4 28 38 28
1634
    ///  23 6 16
1635
    ///\endcode
1636
    ///
1637
    /// The generator is implemented as a struct.
1638
    ///\code
1639
    ///  struct NumberSection {
1640
    ///    std::vector<int>::const_iterator _it, _end;
1641
    ///    NumberSection(const std::vector<int>& data)
1642
    ///      : _it(data.begin()), _end(data.end()) {}
1643
    ///    std::string operator()() {
1644
    ///      int rem_in_line = 4;
1645
    ///      std::ostringstream ls;
1646
    ///      while (rem_in_line > 0 && _it != _end) {
1647
    ///        ls << *(_it++) << ' ';
1648
    ///        --rem_in_line;
1649
    ///      }
1650
    ///      return ls.str();
1651
    ///    }
1652
    ///  };
1653
    ///
1654
    ///  // ...
1655
    ///
1656
    ///  writer.sectionLines("numbers", NumberSection(vec));
1657
    ///\endcode
1658
    template <typename Functor>
1659
    SectionWriter& sectionLines(const std::string& type, Functor functor) {
1660
      LEMON_ASSERT(!type.empty(), "Type is empty.");
1661
      _sections.push_back(std::make_pair(type,
1662
        new _writer_bits::LineSection<Functor>(functor)));
1663
      return *this;
1664
    }
1665

	
1666

	
1667
    /// \brief Add a section writer with stream oriented writing
1668
    ///
1669
    /// The first parameter is the type of the section, the second is
1670
    /// a functor, which takes a \c std::ostream& parameter. The
1671
    /// functor writes the section to the output stream.
1672
    /// \warning The last line must be closed with end-line character.
1673
    template <typename Functor>
1674
    SectionWriter& sectionStream(const std::string& type, Functor functor) {
1675
      LEMON_ASSERT(!type.empty(), "Type is empty.");
1676
      _sections.push_back(std::make_pair(type,
1677
         new _writer_bits::StreamSection<Functor>(functor)));
1678
      return *this;
1679
    }
1680

	
1681
    /// @}
1682

	
1683
  public:
1684

	
1685

	
1686
    /// \name Execution of the writer
1687
    /// @{
1688

	
1689
    /// \brief Start the batch processing
1690
    ///
1691
    /// This function starts the batch processing.
1692
    void run() {
1693

	
1694
      LEMON_ASSERT(_os != 0, "This writer is assigned to an other writer");
1695

	
1696
      for (Sections::iterator it = _sections.begin();
1697
           it != _sections.end(); ++it) {
1698
        (*_os) << '@' << it->first << std::endl;
1699
        it->second->process(*_os);
1700
      }
1701
    }
1702

	
1703
    /// \brief Give back the stream of the writer
1704
    ///
1705
    /// Returns the stream of the writer
1706
    std::ostream& ostream() {
1707
      return *_os;
1708
    }
1709

	
1710
    /// @}
1711

	
1712
  };
1713

	
1714
  /// \brief Return a \ref SectionWriter class
1715
  ///
1716
  /// This function just returns a \ref SectionWriter class.
1717
  /// \relates SectionWriter
1718
  inline SectionWriter sectionWriter(std::ostream& os) {
1719
    SectionWriter tmp(os);
1720
    return tmp;
1721
  }
1722

	
1723
  /// \brief Return a \ref SectionWriter class
1724
  ///
1725
  /// This function just returns a \ref SectionWriter class.
1726
  /// \relates SectionWriter
1727
  inline SectionWriter sectionWriter(const std::string& fn) {
1728
    SectionWriter tmp(fn);
1729
    return tmp;
1730
  }
1731

	
1732
  /// \brief Return a \ref SectionWriter class
1733
  ///
1734
  /// This function just returns a \ref SectionWriter class.
1735
  /// \relates SectionWriter
1736
  inline SectionWriter sectionWriter(const char* fn) {
1737
    SectionWriter tmp(fn);
1738
    return tmp;
1739
  }
1495 1740
}
1496 1741

	
1497 1742
#endif
0 comments (0 inline)