| 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 | } |