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 ↑
Show white space 48 line context
... ...
@@ -16,48 +16,51 @@
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

	
... ...
@@ -283,48 +286,87 @@
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
... ...
@@ -1471,27 +1513,230 @@
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)