| ... | ... |
@@ -28,24 +28,27 @@ |
| 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 |
}; |
| ... | ... |
@@ -295,24 +298,63 @@ |
| 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); |
| ... | ... |
@@ -1483,15 +1525,218 @@ |
| 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)