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)