... | ... |
@@ -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)