dust3d/thirdparty/QuadriFlow/3rd/lemon-1.3.1/lemon/lgf_writer.h

2688 lines
82 KiB
C++
Executable File

/* -*- mode: C++; indent-tabs-mode: nil; -*-
*
* This file is a part of LEMON, a generic C++ optimization library.
*
* Copyright (C) 2003-2013
* Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
* (Egervary Research Group on Combinatorial Optimization, EGRES).
*
* Permission to use, modify and distribute this software is granted
* provided that this copyright notice appears in all copies. For
* precise terms see the accompanying LICENSE file.
*
* This software is provided "AS IS" with no warranty of any kind,
* express or implied, and with no claim as to its suitability for any
* purpose.
*
*/
///\ingroup lemon_io
///\file
///\brief \ref lgf-format "LEMON Graph Format" writer.
#ifndef LEMON_LGF_WRITER_H
#define LEMON_LGF_WRITER_H
#include <iostream>
#include <fstream>
#include <sstream>
#include <algorithm>
#include <vector>
#include <functional>
#include <lemon/core.h>
#include <lemon/maps.h>
#include <lemon/concept_check.h>
#include <lemon/concepts/maps.h>
namespace lemon {
namespace _writer_bits {
template <typename Value>
struct DefaultConverter {
std::string operator()(const Value& value) {
std::ostringstream os;
os << value;
return os.str();
}
};
template <typename T>
bool operator<(const T&, const T&) {
throw FormatError("Label map is not comparable");
}
template <typename _Map>
class MapLess {
public:
typedef _Map Map;
typedef typename Map::Key Item;
private:
const Map& _map;
public:
MapLess(const Map& map) : _map(map) {}
bool operator()(const Item& left, const Item& right) {
return _map[left] < _map[right];
}
};
template <typename _Graph, bool _dir, typename _Map>
class GraphArcMapLess {
public:
typedef _Map Map;
typedef _Graph Graph;
typedef typename Graph::Edge Item;
private:
const Graph& _graph;
const Map& _map;
public:
GraphArcMapLess(const Graph& graph, const Map& map)
: _graph(graph), _map(map) {}
bool operator()(const Item& left, const Item& right) {
return _map[_graph.direct(left, _dir)] <
_map[_graph.direct(right, _dir)];
}
};
template <typename _Item>
class MapStorageBase {
public:
typedef _Item Item;
public:
MapStorageBase() {}
virtual ~MapStorageBase() {}
virtual std::string get(const Item& item) = 0;
virtual void sort(std::vector<Item>&) = 0;
};
template <typename _Item, typename _Map,
typename _Converter = DefaultConverter<typename _Map::Value> >
class MapStorage : public MapStorageBase<_Item> {
public:
typedef _Map Map;
typedef _Converter Converter;
typedef _Item Item;
private:
const Map& _map;
Converter _converter;
public:
MapStorage(const Map& map, const Converter& converter = Converter())
: _map(map), _converter(converter) {}
virtual ~MapStorage() {}
virtual std::string get(const Item& item) {
return _converter(_map[item]);
}
virtual void sort(std::vector<Item>& items) {
MapLess<Map> less(_map);
std::sort(items.begin(), items.end(), less);
}
};
template <typename _Graph, bool _dir, typename _Map,
typename _Converter = DefaultConverter<typename _Map::Value> >
class GraphArcMapStorage : public MapStorageBase<typename _Graph::Edge> {
public:
typedef _Map Map;
typedef _Converter Converter;
typedef _Graph Graph;
typedef typename Graph::Edge Item;
static const bool dir = _dir;
private:
const Graph& _graph;
const Map& _map;
Converter _converter;
public:
GraphArcMapStorage(const Graph& graph, const Map& map,
const Converter& converter = Converter())
: _graph(graph), _map(map), _converter(converter) {}
virtual ~GraphArcMapStorage() {}
virtual std::string get(const Item& item) {
return _converter(_map[_graph.direct(item, dir)]);
}
virtual void sort(std::vector<Item>& items) {
GraphArcMapLess<Graph, dir, Map> less(_graph, _map);
std::sort(items.begin(), items.end(), less);
}
};
class ValueStorageBase {
public:
ValueStorageBase() {}
virtual ~ValueStorageBase() {}
virtual std::string get() = 0;
};
template <typename _Value, typename _Converter = DefaultConverter<_Value> >
class ValueStorage : public ValueStorageBase {
public:
typedef _Value Value;
typedef _Converter Converter;
private:
const Value& _value;
Converter _converter;
public:
ValueStorage(const Value& value, const Converter& converter = Converter())
: _value(value), _converter(converter) {}
virtual std::string get() {
return _converter(_value);
}
};
template <typename Value,
typename Map = std::map<Value, std::string> >
struct MapLookUpConverter {
const Map& _map;
MapLookUpConverter(const Map& map)
: _map(map) {}
std::string operator()(const Value& value) {
typename Map::const_iterator it = _map.find(value);
if (it == _map.end()) {
throw FormatError("Item not found");
}
return it->second;
}
};
template <typename Value,
typename Map1 = std::map<Value, std::string>,
typename Map2 = std::map<Value, std::string> >
struct DoubleMapLookUpConverter {
const Map1& _map1;
const Map2& _map2;
DoubleMapLookUpConverter(const Map1& map1, const Map2& map2)
: _map1(map1), _map2(map2) {}
std::string operator()(const Value& value) {
typename Map1::const_iterator it1 = _map1.find(value);
typename Map1::const_iterator it2 = _map2.find(value);
if (it1 == _map1.end()) {
if (it2 == _map2.end()) {
throw FormatError("Item not found");
} else {
return it2->second;
}
} else {
if (it2 == _map2.end()) {
return it1->second;
} else {
throw FormatError("Item is ambigous");
}
}
}
};
template <typename Graph>
struct GraphArcLookUpConverter {
const Graph& _graph;
const std::map<typename Graph::Edge, std::string>& _map;
GraphArcLookUpConverter(const Graph& graph,
const std::map<typename Graph::Edge,
std::string>& map)
: _graph(graph), _map(map) {}
std::string operator()(const typename Graph::Arc& val) {
typename std::map<typename Graph::Edge, std::string>
::const_iterator it = _map.find(val);
if (it == _map.end()) {
throw FormatError("Item not found");
}
return (_graph.direction(val) ? '+' : '-') + it->second;
}
};
inline bool isWhiteSpace(char c) {
return c == ' ' || c == '\t' || c == '\v' ||
c == '\n' || c == '\r' || c == '\f';
}
inline bool isEscaped(char c) {
return c == '\\' || c == '\"' || c == '\'' ||
c == '\a' || c == '\b';
}
inline static void writeEscape(std::ostream& os, char c) {
switch (c) {
case '\\':
os << "\\\\";
return;
case '\"':
os << "\\\"";
return;
case '\a':
os << "\\a";
return;
case '\b':
os << "\\b";
return;
case '\f':
os << "\\f";
return;
case '\r':
os << "\\r";
return;
case '\n':
os << "\\n";
return;
case '\t':
os << "\\t";
return;
case '\v':
os << "\\v";
return;
default:
if (c < 0x20) {
std::ios::fmtflags flags = os.flags();
os << '\\' << std::oct << static_cast<int>(c);
os.flags(flags);
} else {
os << c;
}
return;
}
}
inline bool requireEscape(const std::string& str) {
if (str.empty() || str[0] == '@') return true;
std::istringstream is(str);
char c;
while (is.get(c)) {
if (isWhiteSpace(c) || isEscaped(c)) {
return true;
}
}
return false;
}
inline std::ostream& writeToken(std::ostream& os, const std::string& str) {
if (requireEscape(str)) {
os << '\"';
for (std::string::const_iterator it = str.begin();
it != str.end(); ++it) {
writeEscape(os, *it);
}
os << '\"';
} else {
os << str;
}
return os;
}
class Section {
public:
virtual ~Section() {}
virtual void process(std::ostream& os) = 0;
};
template <typename Functor>
class LineSection : public Section {
private:
Functor _functor;
public:
LineSection(const Functor& functor) : _functor(functor) {}
virtual ~LineSection() {}
virtual void process(std::ostream& os) {
std::string line;
while (!(line = _functor()).empty()) os << line << std::endl;
}
};
template <typename Functor>
class StreamSection : public Section {
private:
Functor _functor;
public:
StreamSection(const Functor& functor) : _functor(functor) {}
virtual ~StreamSection() {}
virtual void process(std::ostream& os) {
_functor(os);
}
};
}
template <typename DGR>
class DigraphWriter;
template <typename TDGR>
DigraphWriter<TDGR> digraphWriter(const TDGR& digraph,
std::ostream& os = std::cout);
template <typename TDGR>
DigraphWriter<TDGR> digraphWriter(const TDGR& digraph, const std::string& fn);
template <typename TDGR>
DigraphWriter<TDGR> digraphWriter(const TDGR& digraph, const char* fn);
/// \ingroup lemon_io
///
/// \brief \ref lgf-format "LGF" writer for directed graphs
///
/// This utility writes an \ref lgf-format "LGF" file.
///
/// The writing method does a batch processing. The user creates a
/// writer object, then various writing rules can be added to the
/// writer, and eventually the writing is executed with the \c run()
/// member function. A map writing rule can be added to the writer
/// with the \c nodeMap() or \c arcMap() members. An optional
/// converter parameter can also be added as a standard functor
/// converting from the value type of the map to \c std::string. If it
/// is set, it will determine how the value type of the map is written to
/// the output stream. If the functor is not set, then a default
/// conversion will be used. The \c attribute(), \c node() and \c
/// arc() functions are used to add attribute writing rules.
///
///\code
/// DigraphWriter<DGR>(digraph, std::cout).
/// nodeMap("coordinates", coord_map).
/// nodeMap("size", size).
/// nodeMap("title", title).
/// arcMap("capacity", cap_map).
/// node("source", src).
/// node("target", trg).
/// attribute("caption", caption).
/// run();
///\endcode
///
///
/// By default, the writer does not write additional captions to the
/// sections, but they can be give as an optional parameter of
/// the \c nodes(), \c arcs() or \c
/// attributes() functions.
///
/// The \c skipNodes() and \c skipArcs() functions forbid the
/// writing of the sections. If two arc sections should be written
/// to the output, it can be done in two passes, the first pass
/// writes the node section and the first arc section, then the
/// second pass skips the node section and writes just the arc
/// section to the stream. The output stream can be retrieved with
/// the \c ostream() function, hence the second pass can append its
/// output to the output of the first pass.
template <typename DGR>
class DigraphWriter {
public:
typedef DGR Digraph;
TEMPLATE_DIGRAPH_TYPEDEFS(DGR);
private:
std::ostream* _os;
bool local_os;
const DGR& _digraph;
std::string _nodes_caption;
std::string _arcs_caption;
std::string _attributes_caption;
typedef std::map<Node, std::string> NodeIndex;
NodeIndex _node_index;
typedef std::map<Arc, std::string> ArcIndex;
ArcIndex _arc_index;
typedef std::vector<std::pair<std::string,
_writer_bits::MapStorageBase<Node>* > > NodeMaps;
NodeMaps _node_maps;
typedef std::vector<std::pair<std::string,
_writer_bits::MapStorageBase<Arc>* > >ArcMaps;
ArcMaps _arc_maps;
typedef std::vector<std::pair<std::string,
_writer_bits::ValueStorageBase*> > Attributes;
Attributes _attributes;
bool _skip_nodes;
bool _skip_arcs;
public:
/// \brief Constructor
///
/// Construct a directed graph writer, which writes to the given
/// output stream.
DigraphWriter(const DGR& digraph, std::ostream& os = std::cout)
: _os(&os), local_os(false), _digraph(digraph),
_skip_nodes(false), _skip_arcs(false) {}
/// \brief Constructor
///
/// Construct a directed graph writer, which writes to the given
/// output file.
DigraphWriter(const DGR& digraph, const std::string& fn)
: _os(new std::ofstream(fn.c_str())), local_os(true), _digraph(digraph),
_skip_nodes(false), _skip_arcs(false) {
if (!(*_os)) {
delete _os;
throw IoError("Cannot write file", fn);
}
}
/// \brief Constructor
///
/// Construct a directed graph writer, which writes to the given
/// output file.
DigraphWriter(const DGR& digraph, const char* fn)
: _os(new std::ofstream(fn)), local_os(true), _digraph(digraph),
_skip_nodes(false), _skip_arcs(false) {
if (!(*_os)) {
delete _os;
throw IoError("Cannot write file", fn);
}
}
/// \brief Destructor
~DigraphWriter() {
for (typename NodeMaps::iterator it = _node_maps.begin();
it != _node_maps.end(); ++it) {
delete it->second;
}
for (typename ArcMaps::iterator it = _arc_maps.begin();
it != _arc_maps.end(); ++it) {
delete it->second;
}
for (typename Attributes::iterator it = _attributes.begin();
it != _attributes.end(); ++it) {
delete it->second;
}
if (local_os) {
delete _os;
}
}
private:
template <typename TDGR>
friend DigraphWriter<TDGR> digraphWriter(const TDGR& digraph,
std::ostream& os);
template <typename TDGR>
friend DigraphWriter<TDGR> digraphWriter(const TDGR& digraph,
const std::string& fn);
template <typename TDGR>
friend DigraphWriter<TDGR> digraphWriter(const TDGR& digraph,
const char *fn);
DigraphWriter(DigraphWriter& other)
: _os(other._os), local_os(other.local_os), _digraph(other._digraph),
_skip_nodes(other._skip_nodes), _skip_arcs(other._skip_arcs) {
other._os = 0;
other.local_os = false;
_node_index.swap(other._node_index);
_arc_index.swap(other._arc_index);
_node_maps.swap(other._node_maps);
_arc_maps.swap(other._arc_maps);
_attributes.swap(other._attributes);
_nodes_caption = other._nodes_caption;
_arcs_caption = other._arcs_caption;
_attributes_caption = other._attributes_caption;
}
DigraphWriter& operator=(const DigraphWriter&);
public:
/// \name Writing Rules
/// @{
/// \brief Node map writing rule
///
/// Add a node map writing rule to the writer.
template <typename Map>
DigraphWriter& nodeMap(const std::string& caption, const Map& map) {
checkConcept<concepts::ReadMap<Node, typename Map::Value>, Map>();
_writer_bits::MapStorageBase<Node>* storage =
new _writer_bits::MapStorage<Node, Map>(map);
_node_maps.push_back(std::make_pair(caption, storage));
return *this;
}
/// \brief Node map writing rule
///
/// Add a node map writing rule with specialized converter to the
/// writer.
template <typename Map, typename Converter>
DigraphWriter& nodeMap(const std::string& caption, const Map& map,
const Converter& converter = Converter()) {
checkConcept<concepts::ReadMap<Node, typename Map::Value>, Map>();
_writer_bits::MapStorageBase<Node>* storage =
new _writer_bits::MapStorage<Node, Map, Converter>(map, converter);
_node_maps.push_back(std::make_pair(caption, storage));
return *this;
}
/// \brief Arc map writing rule
///
/// Add an arc map writing rule to the writer.
template <typename Map>
DigraphWriter& arcMap(const std::string& caption, const Map& map) {
checkConcept<concepts::ReadMap<Arc, typename Map::Value>, Map>();
_writer_bits::MapStorageBase<Arc>* storage =
new _writer_bits::MapStorage<Arc, Map>(map);
_arc_maps.push_back(std::make_pair(caption, storage));
return *this;
}
/// \brief Arc map writing rule
///
/// Add an arc map writing rule with specialized converter to the
/// writer.
template <typename Map, typename Converter>
DigraphWriter& arcMap(const std::string& caption, const Map& map,
const Converter& converter = Converter()) {
checkConcept<concepts::ReadMap<Arc, typename Map::Value>, Map>();
_writer_bits::MapStorageBase<Arc>* storage =
new _writer_bits::MapStorage<Arc, Map, Converter>(map, converter);
_arc_maps.push_back(std::make_pair(caption, storage));
return *this;
}
/// \brief Attribute writing rule
///
/// Add an attribute writing rule to the writer.
template <typename Value>
DigraphWriter& attribute(const std::string& caption, const Value& value) {
_writer_bits::ValueStorageBase* storage =
new _writer_bits::ValueStorage<Value>(value);
_attributes.push_back(std::make_pair(caption, storage));
return *this;
}
/// \brief Attribute writing rule
///
/// Add an attribute writing rule with specialized converter to the
/// writer.
template <typename Value, typename Converter>
DigraphWriter& attribute(const std::string& caption, const Value& value,
const Converter& converter = Converter()) {
_writer_bits::ValueStorageBase* storage =
new _writer_bits::ValueStorage<Value, Converter>(value, converter);
_attributes.push_back(std::make_pair(caption, storage));
return *this;
}
/// \brief Node writing rule
///
/// Add a node writing rule to the writer.
DigraphWriter& node(const std::string& caption, const Node& node) {
typedef _writer_bits::MapLookUpConverter<Node> Converter;
Converter converter(_node_index);
_writer_bits::ValueStorageBase* storage =
new _writer_bits::ValueStorage<Node, Converter>(node, converter);
_attributes.push_back(std::make_pair(caption, storage));
return *this;
}
/// \brief Arc writing rule
///
/// Add an arc writing rule to writer.
DigraphWriter& arc(const std::string& caption, const Arc& arc) {
typedef _writer_bits::MapLookUpConverter<Arc> Converter;
Converter converter(_arc_index);
_writer_bits::ValueStorageBase* storage =
new _writer_bits::ValueStorage<Arc, Converter>(arc, converter);
_attributes.push_back(std::make_pair(caption, storage));
return *this;
}
/// \name Section Captions
/// @{
/// \brief Add an additional caption to the \c \@nodes section
///
/// Add an additional caption to the \c \@nodes section.
DigraphWriter& nodes(const std::string& caption) {
_nodes_caption = caption;
return *this;
}
/// \brief Add an additional caption to the \c \@arcs section
///
/// Add an additional caption to the \c \@arcs section.
DigraphWriter& arcs(const std::string& caption) {
_arcs_caption = caption;
return *this;
}
/// \brief Add an additional caption to the \c \@attributes section
///
/// Add an additional caption to the \c \@attributes section.
DigraphWriter& attributes(const std::string& caption) {
_attributes_caption = caption;
return *this;
}
/// \name Skipping Section
/// @{
/// \brief Skip writing the node set
///
/// The \c \@nodes section will not be written to the stream.
DigraphWriter& skipNodes() {
LEMON_ASSERT(!_skip_nodes, "Multiple usage of skipNodes() member");
_skip_nodes = true;
return *this;
}
/// \brief Skip writing arc set
///
/// The \c \@arcs section will not be written to the stream.
DigraphWriter& skipArcs() {
LEMON_ASSERT(!_skip_arcs, "Multiple usage of skipArcs() member");
_skip_arcs = true;
return *this;
}
/// @}
private:
void writeNodes() {
_writer_bits::MapStorageBase<Node>* label = 0;
for (typename NodeMaps::iterator it = _node_maps.begin();
it != _node_maps.end(); ++it) {
if (it->first == "label") {
label = it->second;
break;
}
}
*_os << "@nodes";
if (!_nodes_caption.empty()) {
_writer_bits::writeToken(*_os << ' ', _nodes_caption);
}
*_os << std::endl;
if (label == 0) {
*_os << "label" << '\t';
}
for (typename NodeMaps::iterator it = _node_maps.begin();
it != _node_maps.end(); ++it) {
_writer_bits::writeToken(*_os, it->first) << '\t';
}
*_os << std::endl;
std::vector<Node> nodes;
for (NodeIt n(_digraph); n != INVALID; ++n) {
nodes.push_back(n);
}
if (label == 0) {
IdMap<DGR, Node> id_map(_digraph);
_writer_bits::MapLess<IdMap<DGR, Node> > id_less(id_map);
std::sort(nodes.begin(), nodes.end(), id_less);
} else {
label->sort(nodes);
}
for (int i = 0; i < static_cast<int>(nodes.size()); ++i) {
Node n = nodes[i];
if (label == 0) {
std::ostringstream os;
os << _digraph.id(n);
_writer_bits::writeToken(*_os, os.str());
*_os << '\t';
_node_index.insert(std::make_pair(n, os.str()));
}
for (typename NodeMaps::iterator it = _node_maps.begin();
it != _node_maps.end(); ++it) {
std::string value = it->second->get(n);
_writer_bits::writeToken(*_os, value);
if (it->first == "label") {
_node_index.insert(std::make_pair(n, value));
}
*_os << '\t';
}
*_os << std::endl;
}
}
void createNodeIndex() {
_writer_bits::MapStorageBase<Node>* label = 0;
for (typename NodeMaps::iterator it = _node_maps.begin();
it != _node_maps.end(); ++it) {
if (it->first == "label") {
label = it->second;
break;
}
}
if (label == 0) {
for (NodeIt n(_digraph); n != INVALID; ++n) {
std::ostringstream os;
os << _digraph.id(n);
_node_index.insert(std::make_pair(n, os.str()));
}
} else {
for (NodeIt n(_digraph); n != INVALID; ++n) {
std::string value = label->get(n);
_node_index.insert(std::make_pair(n, value));
}
}
}
void writeArcs() {
_writer_bits::MapStorageBase<Arc>* label = 0;
for (typename ArcMaps::iterator it = _arc_maps.begin();
it != _arc_maps.end(); ++it) {
if (it->first == "label") {
label = it->second;
break;
}
}
*_os << "@arcs";
if (!_arcs_caption.empty()) {
_writer_bits::writeToken(*_os << ' ', _arcs_caption);
}
*_os << std::endl;
*_os << '\t' << '\t';
if (label == 0) {
*_os << "label" << '\t';
}
for (typename ArcMaps::iterator it = _arc_maps.begin();
it != _arc_maps.end(); ++it) {
_writer_bits::writeToken(*_os, it->first) << '\t';
}
*_os << std::endl;
std::vector<Arc> arcs;
for (ArcIt n(_digraph); n != INVALID; ++n) {
arcs.push_back(n);
}
if (label == 0) {
IdMap<DGR, Arc> id_map(_digraph);
_writer_bits::MapLess<IdMap<DGR, Arc> > id_less(id_map);
std::sort(arcs.begin(), arcs.end(), id_less);
} else {
label->sort(arcs);
}
for (int i = 0; i < static_cast<int>(arcs.size()); ++i) {
Arc a = arcs[i];
_writer_bits::writeToken(*_os, _node_index.
find(_digraph.source(a))->second);
*_os << '\t';
_writer_bits::writeToken(*_os, _node_index.
find(_digraph.target(a))->second);
*_os << '\t';
if (label == 0) {
std::ostringstream os;
os << _digraph.id(a);
_writer_bits::writeToken(*_os, os.str());
*_os << '\t';
_arc_index.insert(std::make_pair(a, os.str()));
}
for (typename ArcMaps::iterator it = _arc_maps.begin();
it != _arc_maps.end(); ++it) {
std::string value = it->second->get(a);
_writer_bits::writeToken(*_os, value);
if (it->first == "label") {
_arc_index.insert(std::make_pair(a, value));
}
*_os << '\t';
}
*_os << std::endl;
}
}
void createArcIndex() {
_writer_bits::MapStorageBase<Arc>* label = 0;
for (typename ArcMaps::iterator it = _arc_maps.begin();
it != _arc_maps.end(); ++it) {
if (it->first == "label") {
label = it->second;
break;
}
}
if (label == 0) {
for (ArcIt a(_digraph); a != INVALID; ++a) {
std::ostringstream os;
os << _digraph.id(a);
_arc_index.insert(std::make_pair(a, os.str()));
}
} else {
for (ArcIt a(_digraph); a != INVALID; ++a) {
std::string value = label->get(a);
_arc_index.insert(std::make_pair(a, value));
}
}
}
void writeAttributes() {
if (_attributes.empty()) return;
*_os << "@attributes";
if (!_attributes_caption.empty()) {
_writer_bits::writeToken(*_os << ' ', _attributes_caption);
}
*_os << std::endl;
for (typename Attributes::iterator it = _attributes.begin();
it != _attributes.end(); ++it) {
_writer_bits::writeToken(*_os, it->first) << ' ';
_writer_bits::writeToken(*_os, it->second->get());
*_os << std::endl;
}
}
public:
/// \name Execution of the Writer
/// @{
/// \brief Start the batch processing
///
/// This function starts the batch processing.
void run() {
if (!_skip_nodes) {
writeNodes();
} else {
createNodeIndex();
}
if (!_skip_arcs) {
writeArcs();
} else {
createArcIndex();
}
writeAttributes();
}
/// \brief Give back the stream of the writer
///
/// Give back the stream of the writer.
std::ostream& ostream() {
return *_os;
}
/// @}
};
/// \ingroup lemon_io
///
/// \brief Return a \ref lemon::DigraphWriter "DigraphWriter" class
///
/// This function just returns a \ref lemon::DigraphWriter
/// "DigraphWriter" class.
///
/// With this function a digraph can be write to a file or output
/// stream in \ref lgf-format "LGF" format with several maps and
/// attributes. For example, with the following code a network flow
/// problem can be written to the standard output, i.e. a digraph
/// with a \e capacity map on the arcs and \e source and \e target
/// nodes:
///
///\code
///ListDigraph digraph;
///ListDigraph::ArcMap<int> cap(digraph);
///ListDigraph::Node src, trg;
/// // Setting the capacity map and source and target nodes
///digraphWriter(digraph, std::cout).
/// arcMap("capacity", cap).
/// node("source", src).
/// node("target", trg).
/// run();
///\endcode
///
/// For a complete documentation, please see the
/// \ref lemon::DigraphWriter "DigraphWriter"
/// class documentation.
/// \warning Don't forget to put the \ref lemon::DigraphWriter::run() "run()"
/// to the end of the parameter list.
/// \relates DigraphWriter
/// \sa digraphWriter(const TDGR& digraph, const std::string& fn)
/// \sa digraphWriter(const TDGR& digraph, const char* fn)
template <typename TDGR>
DigraphWriter<TDGR> digraphWriter(const TDGR& digraph, std::ostream& os) {
DigraphWriter<TDGR> tmp(digraph, os);
return tmp;
}
/// \brief Return a \ref DigraphWriter class
///
/// This function just returns a \ref DigraphWriter class.
/// \relates DigraphWriter
/// \sa digraphWriter(const TDGR& digraph, std::ostream& os)
template <typename TDGR>
DigraphWriter<TDGR> digraphWriter(const TDGR& digraph,
const std::string& fn) {
DigraphWriter<TDGR> tmp(digraph, fn);
return tmp;
}
/// \brief Return a \ref DigraphWriter class
///
/// This function just returns a \ref DigraphWriter class.
/// \relates DigraphWriter
/// \sa digraphWriter(const TDGR& digraph, std::ostream& os)
template <typename TDGR>
DigraphWriter<TDGR> digraphWriter(const TDGR& digraph, const char* fn) {
DigraphWriter<TDGR> tmp(digraph, fn);
return tmp;
}
template <typename GR>
class GraphWriter;
template <typename TGR>
GraphWriter<TGR> graphWriter(const TGR& graph, std::ostream& os = std::cout);
template <typename TGR>
GraphWriter<TGR> graphWriter(const TGR& graph, const std::string& fn);
template <typename TGR>
GraphWriter<TGR> graphWriter(const TGR& graph, const char* fn);
/// \ingroup lemon_io
///
/// \brief \ref lgf-format "LGF" writer for undirected graphs
///
/// This utility writes an \ref lgf-format "LGF" file.
///
/// It can be used almost the same way as \c DigraphWriter.
/// The only difference is that this class can handle edges and
/// edge maps as well as arcs and arc maps.
///
/// The arc maps are written into the file as two columns, the
/// caption of the columns are the name of the map prefixed with \c
/// '+' and \c '-'. The arcs are written into the \c \@attributes
/// section as a \c '+' or a \c '-' prefix (depends on the direction
/// of the arc) and the label of corresponding edge.
template <typename GR>
class GraphWriter {
public:
typedef GR Graph;
TEMPLATE_GRAPH_TYPEDEFS(GR);
private:
std::ostream* _os;
bool local_os;
const GR& _graph;
std::string _nodes_caption;
std::string _edges_caption;
std::string _attributes_caption;
typedef std::map<Node, std::string> NodeIndex;
NodeIndex _node_index;
typedef std::map<Edge, std::string> EdgeIndex;
EdgeIndex _edge_index;
typedef std::vector<std::pair<std::string,
_writer_bits::MapStorageBase<Node>* > > NodeMaps;
NodeMaps _node_maps;
typedef std::vector<std::pair<std::string,
_writer_bits::MapStorageBase<Edge>* > >EdgeMaps;
EdgeMaps _edge_maps;
typedef std::vector<std::pair<std::string,
_writer_bits::ValueStorageBase*> > Attributes;
Attributes _attributes;
bool _skip_nodes;
bool _skip_edges;
public:
/// \brief Constructor
///
/// Construct an undirected graph writer, which writes to the
/// given output stream.
GraphWriter(const GR& graph, std::ostream& os = std::cout)
: _os(&os), local_os(false), _graph(graph),
_skip_nodes(false), _skip_edges(false) {}
/// \brief Constructor
///
/// Construct a undirected graph writer, which writes to the given
/// output file.
GraphWriter(const GR& graph, const std::string& fn)
: _os(new std::ofstream(fn.c_str())), local_os(true), _graph(graph),
_skip_nodes(false), _skip_edges(false) {
if (!(*_os)) {
delete _os;
throw IoError("Cannot write file", fn);
}
}
/// \brief Constructor
///
/// Construct a undirected graph writer, which writes to the given
/// output file.
GraphWriter(const GR& graph, const char* fn)
: _os(new std::ofstream(fn)), local_os(true), _graph(graph),
_skip_nodes(false), _skip_edges(false) {
if (!(*_os)) {
delete _os;
throw IoError("Cannot write file", fn);
}
}
/// \brief Destructor
~GraphWriter() {
for (typename NodeMaps::iterator it = _node_maps.begin();
it != _node_maps.end(); ++it) {
delete it->second;
}
for (typename EdgeMaps::iterator it = _edge_maps.begin();
it != _edge_maps.end(); ++it) {
delete it->second;
}
for (typename Attributes::iterator it = _attributes.begin();
it != _attributes.end(); ++it) {
delete it->second;
}
if (local_os) {
delete _os;
}
}
private:
template <typename TGR>
friend GraphWriter<TGR> graphWriter(const TGR& graph, std::ostream& os);
template <typename TGR>
friend GraphWriter<TGR> graphWriter(const TGR& graph,
const std::string& fn);
template <typename TGR>
friend GraphWriter<TGR> graphWriter(const TGR& graph, const char *fn);
GraphWriter(GraphWriter& other)
: _os(other._os), local_os(other.local_os), _graph(other._graph),
_skip_nodes(other._skip_nodes), _skip_edges(other._skip_edges) {
other._os = 0;
other.local_os = false;
_node_index.swap(other._node_index);
_edge_index.swap(other._edge_index);
_node_maps.swap(other._node_maps);
_edge_maps.swap(other._edge_maps);
_attributes.swap(other._attributes);
_nodes_caption = other._nodes_caption;
_edges_caption = other._edges_caption;
_attributes_caption = other._attributes_caption;
}
GraphWriter& operator=(const GraphWriter&);
public:
/// \name Writing Rules
/// @{
/// \brief Node map writing rule
///
/// Add a node map writing rule to the writer.
template <typename Map>
GraphWriter& nodeMap(const std::string& caption, const Map& map) {
checkConcept<concepts::ReadMap<Node, typename Map::Value>, Map>();
_writer_bits::MapStorageBase<Node>* storage =
new _writer_bits::MapStorage<Node, Map>(map);
_node_maps.push_back(std::make_pair(caption, storage));
return *this;
}
/// \brief Node map writing rule
///
/// Add a node map writing rule with specialized converter to the
/// writer.
template <typename Map, typename Converter>
GraphWriter& nodeMap(const std::string& caption, const Map& map,
const Converter& converter = Converter()) {
checkConcept<concepts::ReadMap<Node, typename Map::Value>, Map>();
_writer_bits::MapStorageBase<Node>* storage =
new _writer_bits::MapStorage<Node, Map, Converter>(map, converter);
_node_maps.push_back(std::make_pair(caption, storage));
return *this;
}
/// \brief Edge map writing rule
///
/// Add an edge map writing rule to the writer.
template <typename Map>
GraphWriter& edgeMap(const std::string& caption, const Map& map) {
checkConcept<concepts::ReadMap<Edge, typename Map::Value>, Map>();
_writer_bits::MapStorageBase<Edge>* storage =
new _writer_bits::MapStorage<Edge, Map>(map);
_edge_maps.push_back(std::make_pair(caption, storage));
return *this;
}
/// \brief Edge map writing rule
///
/// Add an edge map writing rule with specialized converter to the
/// writer.
template <typename Map, typename Converter>
GraphWriter& edgeMap(const std::string& caption, const Map& map,
const Converter& converter = Converter()) {
checkConcept<concepts::ReadMap<Edge, typename Map::Value>, Map>();
_writer_bits::MapStorageBase<Edge>* storage =
new _writer_bits::MapStorage<Edge, Map, Converter>(map, converter);
_edge_maps.push_back(std::make_pair(caption, storage));
return *this;
}
/// \brief Arc map writing rule
///
/// Add an arc map writing rule to the writer.
template <typename Map>
GraphWriter& arcMap(const std::string& caption, const Map& map) {
checkConcept<concepts::ReadMap<Arc, typename Map::Value>, Map>();
_writer_bits::MapStorageBase<Edge>* forward_storage =
new _writer_bits::GraphArcMapStorage<GR, true, Map>(_graph, map);
_edge_maps.push_back(std::make_pair('+' + caption, forward_storage));
_writer_bits::MapStorageBase<Edge>* backward_storage =
new _writer_bits::GraphArcMapStorage<GR, false, Map>(_graph, map);
_edge_maps.push_back(std::make_pair('-' + caption, backward_storage));
return *this;
}
/// \brief Arc map writing rule
///
/// Add an arc map writing rule with specialized converter to the
/// writer.
template <typename Map, typename Converter>
GraphWriter& arcMap(const std::string& caption, const Map& map,
const Converter& converter = Converter()) {
checkConcept<concepts::ReadMap<Arc, typename Map::Value>, Map>();
_writer_bits::MapStorageBase<Edge>* forward_storage =
new _writer_bits::GraphArcMapStorage<GR, true, Map, Converter>
(_graph, map, converter);
_edge_maps.push_back(std::make_pair('+' + caption, forward_storage));
_writer_bits::MapStorageBase<Edge>* backward_storage =
new _writer_bits::GraphArcMapStorage<GR, false, Map, Converter>
(_graph, map, converter);
_edge_maps.push_back(std::make_pair('-' + caption, backward_storage));
return *this;
}
/// \brief Attribute writing rule
///
/// Add an attribute writing rule to the writer.
template <typename Value>
GraphWriter& attribute(const std::string& caption, const Value& value) {
_writer_bits::ValueStorageBase* storage =
new _writer_bits::ValueStorage<Value>(value);
_attributes.push_back(std::make_pair(caption, storage));
return *this;
}
/// \brief Attribute writing rule
///
/// Add an attribute writing rule with specialized converter to the
/// writer.
template <typename Value, typename Converter>
GraphWriter& attribute(const std::string& caption, const Value& value,
const Converter& converter = Converter()) {
_writer_bits::ValueStorageBase* storage =
new _writer_bits::ValueStorage<Value, Converter>(value, converter);
_attributes.push_back(std::make_pair(caption, storage));
return *this;
}
/// \brief Node writing rule
///
/// Add a node writing rule to the writer.
GraphWriter& node(const std::string& caption, const Node& node) {
typedef _writer_bits::MapLookUpConverter<Node> Converter;
Converter converter(_node_index);
_writer_bits::ValueStorageBase* storage =
new _writer_bits::ValueStorage<Node, Converter>(node, converter);
_attributes.push_back(std::make_pair(caption, storage));
return *this;
}
/// \brief Edge writing rule
///
/// Add an edge writing rule to writer.
GraphWriter& edge(const std::string& caption, const Edge& edge) {
typedef _writer_bits::MapLookUpConverter<Edge> Converter;
Converter converter(_edge_index);
_writer_bits::ValueStorageBase* storage =
new _writer_bits::ValueStorage<Edge, Converter>(edge, converter);
_attributes.push_back(std::make_pair(caption, storage));
return *this;
}
/// \brief Arc writing rule
///
/// Add an arc writing rule to writer.
GraphWriter& arc(const std::string& caption, const Arc& arc) {
typedef _writer_bits::GraphArcLookUpConverter<GR> Converter;
Converter converter(_graph, _edge_index);
_writer_bits::ValueStorageBase* storage =
new _writer_bits::ValueStorage<Arc, Converter>(arc, converter);
_attributes.push_back(std::make_pair(caption, storage));
return *this;
}
/// \name Section Captions
/// @{
/// \brief Add an additional caption to the \c \@nodes section
///
/// Add an additional caption to the \c \@nodes section.
GraphWriter& nodes(const std::string& caption) {
_nodes_caption = caption;
return *this;
}
/// \brief Add an additional caption to the \c \@edges section
///
/// Add an additional caption to the \c \@edges section.
GraphWriter& edges(const std::string& caption) {
_edges_caption = caption;
return *this;
}
/// \brief Add an additional caption to the \c \@attributes section
///
/// Add an additional caption to the \c \@attributes section.
GraphWriter& attributes(const std::string& caption) {
_attributes_caption = caption;
return *this;
}
/// \name Skipping Section
/// @{
/// \brief Skip writing the node set
///
/// The \c \@nodes section will not be written to the stream.
GraphWriter& skipNodes() {
LEMON_ASSERT(!_skip_nodes, "Multiple usage of skipNodes() member");
_skip_nodes = true;
return *this;
}
/// \brief Skip writing edge set
///
/// The \c \@edges section will not be written to the stream.
GraphWriter& skipEdges() {
LEMON_ASSERT(!_skip_edges, "Multiple usage of skipEdges() member");
_skip_edges = true;
return *this;
}
/// @}
private:
void writeNodes() {
_writer_bits::MapStorageBase<Node>* label = 0;
for (typename NodeMaps::iterator it = _node_maps.begin();
it != _node_maps.end(); ++it) {
if (it->first == "label") {
label = it->second;
break;
}
}
*_os << "@nodes";
if (!_nodes_caption.empty()) {
_writer_bits::writeToken(*_os << ' ', _nodes_caption);
}
*_os << std::endl;
if (label == 0) {
*_os << "label" << '\t';
}
for (typename NodeMaps::iterator it = _node_maps.begin();
it != _node_maps.end(); ++it) {
_writer_bits::writeToken(*_os, it->first) << '\t';
}
*_os << std::endl;
std::vector<Node> nodes;
for (NodeIt n(_graph); n != INVALID; ++n) {
nodes.push_back(n);
}
if (label == 0) {
IdMap<GR, Node> id_map(_graph);
_writer_bits::MapLess<IdMap<GR, Node> > id_less(id_map);
std::sort(nodes.begin(), nodes.end(), id_less);
} else {
label->sort(nodes);
}
for (int i = 0; i < static_cast<int>(nodes.size()); ++i) {
Node n = nodes[i];
if (label == 0) {
std::ostringstream os;
os << _graph.id(n);
_writer_bits::writeToken(*_os, os.str());
*_os << '\t';
_node_index.insert(std::make_pair(n, os.str()));
}
for (typename NodeMaps::iterator it = _node_maps.begin();
it != _node_maps.end(); ++it) {
std::string value = it->second->get(n);
_writer_bits::writeToken(*_os, value);
if (it->first == "label") {
_node_index.insert(std::make_pair(n, value));
}
*_os << '\t';
}
*_os << std::endl;
}
}
void createNodeIndex() {
_writer_bits::MapStorageBase<Node>* label = 0;
for (typename NodeMaps::iterator it = _node_maps.begin();
it != _node_maps.end(); ++it) {
if (it->first == "label") {
label = it->second;
break;
}
}
if (label == 0) {
for (NodeIt n(_graph); n != INVALID; ++n) {
std::ostringstream os;
os << _graph.id(n);
_node_index.insert(std::make_pair(n, os.str()));
}
} else {
for (NodeIt n(_graph); n != INVALID; ++n) {
std::string value = label->get(n);
_node_index.insert(std::make_pair(n, value));
}
}
}
void writeEdges() {
_writer_bits::MapStorageBase<Edge>* label = 0;
for (typename EdgeMaps::iterator it = _edge_maps.begin();
it != _edge_maps.end(); ++it) {
if (it->first == "label") {
label = it->second;
break;
}
}
*_os << "@edges";
if (!_edges_caption.empty()) {
_writer_bits::writeToken(*_os << ' ', _edges_caption);
}
*_os << std::endl;
*_os << '\t' << '\t';
if (label == 0) {
*_os << "label" << '\t';
}
for (typename EdgeMaps::iterator it = _edge_maps.begin();
it != _edge_maps.end(); ++it) {
_writer_bits::writeToken(*_os, it->first) << '\t';
}
*_os << std::endl;
std::vector<Edge> edges;
for (EdgeIt n(_graph); n != INVALID; ++n) {
edges.push_back(n);
}
if (label == 0) {
IdMap<GR, Edge> id_map(_graph);
_writer_bits::MapLess<IdMap<GR, Edge> > id_less(id_map);
std::sort(edges.begin(), edges.end(), id_less);
} else {
label->sort(edges);
}
for (int i = 0; i < static_cast<int>(edges.size()); ++i) {
Edge e = edges[i];
_writer_bits::writeToken(*_os, _node_index.
find(_graph.u(e))->second);
*_os << '\t';
_writer_bits::writeToken(*_os, _node_index.
find(_graph.v(e))->second);
*_os << '\t';
if (label == 0) {
std::ostringstream os;
os << _graph.id(e);
_writer_bits::writeToken(*_os, os.str());
*_os << '\t';
_edge_index.insert(std::make_pair(e, os.str()));
}
for (typename EdgeMaps::iterator it = _edge_maps.begin();
it != _edge_maps.end(); ++it) {
std::string value = it->second->get(e);
_writer_bits::writeToken(*_os, value);
if (it->first == "label") {
_edge_index.insert(std::make_pair(e, value));
}
*_os << '\t';
}
*_os << std::endl;
}
}
void createEdgeIndex() {
_writer_bits::MapStorageBase<Edge>* label = 0;
for (typename EdgeMaps::iterator it = _edge_maps.begin();
it != _edge_maps.end(); ++it) {
if (it->first == "label") {
label = it->second;
break;
}
}
if (label == 0) {
for (EdgeIt e(_graph); e != INVALID; ++e) {
std::ostringstream os;
os << _graph.id(e);
_edge_index.insert(std::make_pair(e, os.str()));
}
} else {
for (EdgeIt e(_graph); e != INVALID; ++e) {
std::string value = label->get(e);
_edge_index.insert(std::make_pair(e, value));
}
}
}
void writeAttributes() {
if (_attributes.empty()) return;
*_os << "@attributes";
if (!_attributes_caption.empty()) {
_writer_bits::writeToken(*_os << ' ', _attributes_caption);
}
*_os << std::endl;
for (typename Attributes::iterator it = _attributes.begin();
it != _attributes.end(); ++it) {
_writer_bits::writeToken(*_os, it->first) << ' ';
_writer_bits::writeToken(*_os, it->second->get());
*_os << std::endl;
}
}
public:
/// \name Execution of the Writer
/// @{
/// \brief Start the batch processing
///
/// This function starts the batch processing.
void run() {
if (!_skip_nodes) {
writeNodes();
} else {
createNodeIndex();
}
if (!_skip_edges) {
writeEdges();
} else {
createEdgeIndex();
}
writeAttributes();
}
/// \brief Give back the stream of the writer
///
/// Give back the stream of the writer
std::ostream& ostream() {
return *_os;
}
/// @}
};
/// \ingroup lemon_io
///
/// \brief Return a \ref lemon::GraphWriter "GraphWriter" class
///
/// This function just returns a \ref lemon::GraphWriter "GraphWriter" class.
///
/// With this function a graph can be write to a file or output
/// stream in \ref lgf-format "LGF" format with several maps and
/// attributes. For example, with the following code a weighted
/// matching problem can be written to the standard output, i.e. a
/// graph with a \e weight map on the edges:
///
///\code
///ListGraph graph;
///ListGraph::EdgeMap<int> weight(graph);
/// // Setting the weight map
///graphWriter(graph, std::cout).
/// edgeMap("weight", weight).
/// run();
///\endcode
///
/// For a complete documentation, please see the
/// \ref lemon::GraphWriter "GraphWriter"
/// class documentation.
/// \warning Don't forget to put the \ref lemon::GraphWriter::run() "run()"
/// to the end of the parameter list.
/// \relates GraphWriter
/// \sa graphWriter(const TGR& graph, const std::string& fn)
/// \sa graphWriter(const TGR& graph, const char* fn)
template <typename TGR>
GraphWriter<TGR> graphWriter(const TGR& graph, std::ostream& os) {
GraphWriter<TGR> tmp(graph, os);
return tmp;
}
/// \brief Return a \ref GraphWriter class
///
/// This function just returns a \ref GraphWriter class.
/// \relates GraphWriter
/// \sa graphWriter(const TGR& graph, std::ostream& os)
template <typename TGR>
GraphWriter<TGR> graphWriter(const TGR& graph, const std::string& fn) {
GraphWriter<TGR> tmp(graph, fn);
return tmp;
}
/// \brief Return a \ref GraphWriter class
///
/// This function just returns a \ref GraphWriter class.
/// \relates GraphWriter
/// \sa graphWriter(const TGR& graph, std::ostream& os)
template <typename TGR>
GraphWriter<TGR> graphWriter(const TGR& graph, const char* fn) {
GraphWriter<TGR> tmp(graph, fn);
return tmp;
}
template <typename BGR>
class BpGraphWriter;
template <typename TBGR>
BpGraphWriter<TBGR> bpGraphWriter(const TBGR& graph,
std::ostream& os = std::cout);
template <typename TBGR>
BpGraphWriter<TBGR> bpGraphWriter(const TBGR& graph, const std::string& fn);
template <typename TBGR>
BpGraphWriter<TBGR> bpGraphWriter(const TBGR& graph, const char* fn);
/// \ingroup lemon_io
///
/// \brief \ref lgf-format "LGF" writer for undirected bipartite graphs
///
/// This utility writes an \ref lgf-format "LGF" file.
///
/// It can be used almost the same way as \c GraphWriter, but it
/// reads the red and blue nodes from separate sections, and these
/// sections can contain different set of maps.
///
/// The red and blue node maps are written to the corresponding
/// sections. The node maps are written to both of these sections
/// with the same map name.
template <typename BGR>
class BpGraphWriter {
public:
typedef BGR BpGraph;
TEMPLATE_BPGRAPH_TYPEDEFS(BGR);
private:
std::ostream* _os;
bool local_os;
const BGR& _graph;
std::string _nodes_caption;
std::string _edges_caption;
std::string _attributes_caption;
typedef std::map<Node, std::string> RedNodeIndex;
RedNodeIndex _red_node_index;
typedef std::map<Node, std::string> BlueNodeIndex;
BlueNodeIndex _blue_node_index;
typedef std::map<Edge, std::string> EdgeIndex;
EdgeIndex _edge_index;
typedef std::vector<std::pair<std::string,
_writer_bits::MapStorageBase<RedNode>* > > RedNodeMaps;
RedNodeMaps _red_node_maps;
typedef std::vector<std::pair<std::string,
_writer_bits::MapStorageBase<BlueNode>* > > BlueNodeMaps;
BlueNodeMaps _blue_node_maps;
typedef std::vector<std::pair<std::string,
_writer_bits::MapStorageBase<Edge>* > >EdgeMaps;
EdgeMaps _edge_maps;
typedef std::vector<std::pair<std::string,
_writer_bits::ValueStorageBase*> > Attributes;
Attributes _attributes;
bool _skip_nodes;
bool _skip_edges;
public:
/// \brief Constructor
///
/// Construct a bipartite graph writer, which writes to the given
/// output stream.
BpGraphWriter(const BGR& graph, std::ostream& os = std::cout)
: _os(&os), local_os(false), _graph(graph),
_skip_nodes(false), _skip_edges(false) {}
/// \brief Constructor
///
/// Construct a bipartite graph writer, which writes to the given
/// output file.
BpGraphWriter(const BGR& graph, const std::string& fn)
: _os(new std::ofstream(fn.c_str())), local_os(true), _graph(graph),
_skip_nodes(false), _skip_edges(false) {
if (!(*_os)) {
delete _os;
throw IoError("Cannot write file", fn);
}
}
/// \brief Constructor
///
/// Construct a bipartite graph writer, which writes to the given
/// output file.
BpGraphWriter(const BGR& graph, const char* fn)
: _os(new std::ofstream(fn)), local_os(true), _graph(graph),
_skip_nodes(false), _skip_edges(false) {
if (!(*_os)) {
delete _os;
throw IoError("Cannot write file", fn);
}
}
/// \brief Destructor
~BpGraphWriter() {
for (typename RedNodeMaps::iterator it = _red_node_maps.begin();
it != _red_node_maps.end(); ++it) {
delete it->second;
}
for (typename BlueNodeMaps::iterator it = _blue_node_maps.begin();
it != _blue_node_maps.end(); ++it) {
delete it->second;
}
for (typename EdgeMaps::iterator it = _edge_maps.begin();
it != _edge_maps.end(); ++it) {
delete it->second;
}
for (typename Attributes::iterator it = _attributes.begin();
it != _attributes.end(); ++it) {
delete it->second;
}
if (local_os) {
delete _os;
}
}
private:
template <typename TBGR>
friend BpGraphWriter<TBGR> bpGraphWriter(const TBGR& graph,
std::ostream& os);
template <typename TBGR>
friend BpGraphWriter<TBGR> bpGraphWriter(const TBGR& graph,
const std::string& fn);
template <typename TBGR>
friend BpGraphWriter<TBGR> bpGraphWriter(const TBGR& graph, const char *fn);
BpGraphWriter(BpGraphWriter& other)
: _os(other._os), local_os(other.local_os), _graph(other._graph),
_skip_nodes(other._skip_nodes), _skip_edges(other._skip_edges) {
other._os = 0;
other.local_os = false;
_red_node_index.swap(other._red_node_index);
_blue_node_index.swap(other._blue_node_index);
_edge_index.swap(other._edge_index);
_red_node_maps.swap(other._red_node_maps);
_blue_node_maps.swap(other._blue_node_maps);
_edge_maps.swap(other._edge_maps);
_attributes.swap(other._attributes);
_nodes_caption = other._nodes_caption;
_edges_caption = other._edges_caption;
_attributes_caption = other._attributes_caption;
}
BpGraphWriter& operator=(const BpGraphWriter&);
public:
/// \name Writing Rules
/// @{
/// \brief Node map writing rule
///
/// Add a node map writing rule to the writer.
template <typename Map>
BpGraphWriter& nodeMap(const std::string& caption, const Map& map) {
checkConcept<concepts::ReadMap<Node, typename Map::Value>, Map>();
_writer_bits::MapStorageBase<RedNode>* red_storage =
new _writer_bits::MapStorage<RedNode, Map>(map);
_red_node_maps.push_back(std::make_pair(caption, red_storage));
_writer_bits::MapStorageBase<BlueNode>* blue_storage =
new _writer_bits::MapStorage<BlueNode, Map>(map);
_blue_node_maps.push_back(std::make_pair(caption, blue_storage));
return *this;
}
/// \brief Node map writing rule
///
/// Add a node map writing rule with specialized converter to the
/// writer.
template <typename Map, typename Converter>
BpGraphWriter& nodeMap(const std::string& caption, const Map& map,
const Converter& converter = Converter()) {
checkConcept<concepts::ReadMap<Node, typename Map::Value>, Map>();
_writer_bits::MapStorageBase<RedNode>* red_storage =
new _writer_bits::MapStorage<RedNode, Map, Converter>(map, converter);
_red_node_maps.push_back(std::make_pair(caption, red_storage));
_writer_bits::MapStorageBase<BlueNode>* blue_storage =
new _writer_bits::MapStorage<BlueNode, Map, Converter>(map, converter);
_blue_node_maps.push_back(std::make_pair(caption, blue_storage));
return *this;
}
/// \brief Red node map writing rule
///
/// Add a red node map writing rule to the writer.
template <typename Map>
BpGraphWriter& redNodeMap(const std::string& caption, const Map& map) {
checkConcept<concepts::ReadMap<RedNode, typename Map::Value>, Map>();
_writer_bits::MapStorageBase<RedNode>* storage =
new _writer_bits::MapStorage<RedNode, Map>(map);
_red_node_maps.push_back(std::make_pair(caption, storage));
return *this;
}
/// \brief Red node map writing rule
///
/// Add a red node map writing rule with specialized converter to the
/// writer.
template <typename Map, typename Converter>
BpGraphWriter& redNodeMap(const std::string& caption, const Map& map,
const Converter& converter = Converter()) {
checkConcept<concepts::ReadMap<RedNode, typename Map::Value>, Map>();
_writer_bits::MapStorageBase<RedNode>* storage =
new _writer_bits::MapStorage<RedNode, Map, Converter>(map, converter);
_red_node_maps.push_back(std::make_pair(caption, storage));
return *this;
}
/// \brief Blue node map writing rule
///
/// Add a blue node map writing rule to the writer.
template <typename Map>
BpGraphWriter& blueNodeMap(const std::string& caption, const Map& map) {
checkConcept<concepts::ReadMap<BlueNode, typename Map::Value>, Map>();
_writer_bits::MapStorageBase<BlueNode>* storage =
new _writer_bits::MapStorage<BlueNode, Map>(map);
_blue_node_maps.push_back(std::make_pair(caption, storage));
return *this;
}
/// \brief Blue node map writing rule
///
/// Add a blue node map writing rule with specialized converter to the
/// writer.
template <typename Map, typename Converter>
BpGraphWriter& blueNodeMap(const std::string& caption, const Map& map,
const Converter& converter = Converter()) {
checkConcept<concepts::ReadMap<BlueNode, typename Map::Value>, Map>();
_writer_bits::MapStorageBase<BlueNode>* storage =
new _writer_bits::MapStorage<BlueNode, Map, Converter>(map, converter);
_blue_node_maps.push_back(std::make_pair(caption, storage));
return *this;
}
/// \brief Edge map writing rule
///
/// Add an edge map writing rule to the writer.
template <typename Map>
BpGraphWriter& edgeMap(const std::string& caption, const Map& map) {
checkConcept<concepts::ReadMap<Edge, typename Map::Value>, Map>();
_writer_bits::MapStorageBase<Edge>* storage =
new _writer_bits::MapStorage<Edge, Map>(map);
_edge_maps.push_back(std::make_pair(caption, storage));
return *this;
}
/// \brief Edge map writing rule
///
/// Add an edge map writing rule with specialized converter to the
/// writer.
template <typename Map, typename Converter>
BpGraphWriter& edgeMap(const std::string& caption, const Map& map,
const Converter& converter = Converter()) {
checkConcept<concepts::ReadMap<Edge, typename Map::Value>, Map>();
_writer_bits::MapStorageBase<Edge>* storage =
new _writer_bits::MapStorage<Edge, Map, Converter>(map, converter);
_edge_maps.push_back(std::make_pair(caption, storage));
return *this;
}
/// \brief Arc map writing rule
///
/// Add an arc map writing rule to the writer.
template <typename Map>
BpGraphWriter& arcMap(const std::string& caption, const Map& map) {
checkConcept<concepts::ReadMap<Arc, typename Map::Value>, Map>();
_writer_bits::MapStorageBase<Edge>* forward_storage =
new _writer_bits::GraphArcMapStorage<BGR, true, Map>(_graph, map);
_edge_maps.push_back(std::make_pair('+' + caption, forward_storage));
_writer_bits::MapStorageBase<Edge>* backward_storage =
new _writer_bits::GraphArcMapStorage<BGR, false, Map>(_graph, map);
_edge_maps.push_back(std::make_pair('-' + caption, backward_storage));
return *this;
}
/// \brief Arc map writing rule
///
/// Add an arc map writing rule with specialized converter to the
/// writer.
template <typename Map, typename Converter>
BpGraphWriter& arcMap(const std::string& caption, const Map& map,
const Converter& converter = Converter()) {
checkConcept<concepts::ReadMap<Arc, typename Map::Value>, Map>();
_writer_bits::MapStorageBase<Edge>* forward_storage =
new _writer_bits::GraphArcMapStorage<BGR, true, Map, Converter>
(_graph, map, converter);
_edge_maps.push_back(std::make_pair('+' + caption, forward_storage));
_writer_bits::MapStorageBase<Edge>* backward_storage =
new _writer_bits::GraphArcMapStorage<BGR, false, Map, Converter>
(_graph, map, converter);
_edge_maps.push_back(std::make_pair('-' + caption, backward_storage));
return *this;
}
/// \brief Attribute writing rule
///
/// Add an attribute writing rule to the writer.
template <typename Value>
BpGraphWriter& attribute(const std::string& caption, const Value& value) {
_writer_bits::ValueStorageBase* storage =
new _writer_bits::ValueStorage<Value>(value);
_attributes.push_back(std::make_pair(caption, storage));
return *this;
}
/// \brief Attribute writing rule
///
/// Add an attribute writing rule with specialized converter to the
/// writer.
template <typename Value, typename Converter>
BpGraphWriter& attribute(const std::string& caption, const Value& value,
const Converter& converter = Converter()) {
_writer_bits::ValueStorageBase* storage =
new _writer_bits::ValueStorage<Value, Converter>(value, converter);
_attributes.push_back(std::make_pair(caption, storage));
return *this;
}
/// \brief Node writing rule
///
/// Add a node writing rule to the writer.
BpGraphWriter& node(const std::string& caption, const Node& node) {
typedef _writer_bits::DoubleMapLookUpConverter<
Node, RedNodeIndex, BlueNodeIndex> Converter;
Converter converter(_red_node_index, _blue_node_index);
_writer_bits::ValueStorageBase* storage =
new _writer_bits::ValueStorage<Node, Converter>(node, converter);
_attributes.push_back(std::make_pair(caption, storage));
return *this;
}
/// \brief Red node writing rule
///
/// Add a red node writing rule to the writer.
BpGraphWriter& redNode(const std::string& caption, const RedNode& node) {
typedef _writer_bits::MapLookUpConverter<Node> Converter;
Converter converter(_red_node_index);
_writer_bits::ValueStorageBase* storage =
new _writer_bits::ValueStorage<Node, Converter>(node, converter);
_attributes.push_back(std::make_pair(caption, storage));
return *this;
}
/// \brief Blue node writing rule
///
/// Add a blue node writing rule to the writer.
BpGraphWriter& blueNode(const std::string& caption, const BlueNode& node) {
typedef _writer_bits::MapLookUpConverter<Node> Converter;
Converter converter(_blue_node_index);
_writer_bits::ValueStorageBase* storage =
new _writer_bits::ValueStorage<Node, Converter>(node, converter);
_attributes.push_back(std::make_pair(caption, storage));
return *this;
}
/// \brief Edge writing rule
///
/// Add an edge writing rule to writer.
BpGraphWriter& edge(const std::string& caption, const Edge& edge) {
typedef _writer_bits::MapLookUpConverter<Edge> Converter;
Converter converter(_edge_index);
_writer_bits::ValueStorageBase* storage =
new _writer_bits::ValueStorage<Edge, Converter>(edge, converter);
_attributes.push_back(std::make_pair(caption, storage));
return *this;
}
/// \brief Arc writing rule
///
/// Add an arc writing rule to writer.
BpGraphWriter& arc(const std::string& caption, const Arc& arc) {
typedef _writer_bits::GraphArcLookUpConverter<BGR> Converter;
Converter converter(_graph, _edge_index);
_writer_bits::ValueStorageBase* storage =
new _writer_bits::ValueStorage<Arc, Converter>(arc, converter);
_attributes.push_back(std::make_pair(caption, storage));
return *this;
}
/// \name Section Captions
/// @{
/// \brief Add an additional caption to the \c \@red_nodes and
/// \c \@blue_nodes section
///
/// Add an additional caption to the \c \@red_nodes and \c
/// \@blue_nodes section.
BpGraphWriter& nodes(const std::string& caption) {
_nodes_caption = caption;
return *this;
}
/// \brief Add an additional caption to the \c \@edges section
///
/// Add an additional caption to the \c \@edges section.
BpGraphWriter& edges(const std::string& caption) {
_edges_caption = caption;
return *this;
}
/// \brief Add an additional caption to the \c \@attributes section
///
/// Add an additional caption to the \c \@attributes section.
BpGraphWriter& attributes(const std::string& caption) {
_attributes_caption = caption;
return *this;
}
/// \name Skipping Section
/// @{
/// \brief Skip writing the node set
///
/// The \c \@red_nodes and \c \@blue_nodes section will not be
/// written to the stream.
BpGraphWriter& skipNodes() {
LEMON_ASSERT(!_skip_nodes, "Multiple usage of skipNodes() member");
_skip_nodes = true;
return *this;
}
/// \brief Skip writing edge set
///
/// The \c \@edges section will not be written to the stream.
BpGraphWriter& skipEdges() {
LEMON_ASSERT(!_skip_edges, "Multiple usage of skipEdges() member");
_skip_edges = true;
return *this;
}
/// @}
private:
void writeRedNodes() {
_writer_bits::MapStorageBase<RedNode>* label = 0;
for (typename RedNodeMaps::iterator it = _red_node_maps.begin();
it != _red_node_maps.end(); ++it) {
if (it->first == "label") {
label = it->second;
break;
}
}
*_os << "@red_nodes";
if (!_nodes_caption.empty()) {
_writer_bits::writeToken(*_os << ' ', _nodes_caption);
}
*_os << std::endl;
if (label == 0) {
*_os << "label" << '\t';
}
for (typename RedNodeMaps::iterator it = _red_node_maps.begin();
it != _red_node_maps.end(); ++it) {
_writer_bits::writeToken(*_os, it->first) << '\t';
}
*_os << std::endl;
std::vector<RedNode> nodes;
for (RedNodeIt n(_graph); n != INVALID; ++n) {
nodes.push_back(n);
}
if (label == 0) {
IdMap<BGR, Node> id_map(_graph);
_writer_bits::MapLess<IdMap<BGR, Node> > id_less(id_map);
std::sort(nodes.begin(), nodes.end(), id_less);
} else {
label->sort(nodes);
}
for (int i = 0; i < static_cast<int>(nodes.size()); ++i) {
RedNode n = nodes[i];
if (label == 0) {
std::ostringstream os;
os << _graph.id(static_cast<Node>(n));
_writer_bits::writeToken(*_os, os.str());
*_os << '\t';
_red_node_index.insert(std::make_pair(n, os.str()));
}
for (typename RedNodeMaps::iterator it = _red_node_maps.begin();
it != _red_node_maps.end(); ++it) {
std::string value = it->second->get(n);
_writer_bits::writeToken(*_os, value);
if (it->first == "label") {
_red_node_index.insert(std::make_pair(n, value));
}
*_os << '\t';
}
*_os << std::endl;
}
}
void writeBlueNodes() {
_writer_bits::MapStorageBase<BlueNode>* label = 0;
for (typename BlueNodeMaps::iterator it = _blue_node_maps.begin();
it != _blue_node_maps.end(); ++it) {
if (it->first == "label") {
label = it->second;
break;
}
}
*_os << "@blue_nodes";
if (!_nodes_caption.empty()) {
_writer_bits::writeToken(*_os << ' ', _nodes_caption);
}
*_os << std::endl;
if (label == 0) {
*_os << "label" << '\t';
}
for (typename BlueNodeMaps::iterator it = _blue_node_maps.begin();
it != _blue_node_maps.end(); ++it) {
_writer_bits::writeToken(*_os, it->first) << '\t';
}
*_os << std::endl;
std::vector<BlueNode> nodes;
for (BlueNodeIt n(_graph); n != INVALID; ++n) {
nodes.push_back(n);
}
if (label == 0) {
IdMap<BGR, Node> id_map(_graph);
_writer_bits::MapLess<IdMap<BGR, Node> > id_less(id_map);
std::sort(nodes.begin(), nodes.end(), id_less);
} else {
label->sort(nodes);
}
for (int i = 0; i < static_cast<int>(nodes.size()); ++i) {
BlueNode n = nodes[i];
if (label == 0) {
std::ostringstream os;
os << _graph.id(static_cast<Node>(n));
_writer_bits::writeToken(*_os, os.str());
*_os << '\t';
_blue_node_index.insert(std::make_pair(n, os.str()));
}
for (typename BlueNodeMaps::iterator it = _blue_node_maps.begin();
it != _blue_node_maps.end(); ++it) {
std::string value = it->second->get(n);
_writer_bits::writeToken(*_os, value);
if (it->first == "label") {
_blue_node_index.insert(std::make_pair(n, value));
}
*_os << '\t';
}
*_os << std::endl;
}
}
void createRedNodeIndex() {
_writer_bits::MapStorageBase<RedNode>* label = 0;
for (typename RedNodeMaps::iterator it = _red_node_maps.begin();
it != _red_node_maps.end(); ++it) {
if (it->first == "label") {
label = it->second;
break;
}
}
if (label == 0) {
for (RedNodeIt n(_graph); n != INVALID; ++n) {
std::ostringstream os;
os << _graph.id(n);
_red_node_index.insert(std::make_pair(n, os.str()));
}
} else {
for (RedNodeIt n(_graph); n != INVALID; ++n) {
std::string value = label->get(n);
_red_node_index.insert(std::make_pair(n, value));
}
}
}
void createBlueNodeIndex() {
_writer_bits::MapStorageBase<BlueNode>* label = 0;
for (typename BlueNodeMaps::iterator it = _blue_node_maps.begin();
it != _blue_node_maps.end(); ++it) {
if (it->first == "label") {
label = it->second;
break;
}
}
if (label == 0) {
for (BlueNodeIt n(_graph); n != INVALID; ++n) {
std::ostringstream os;
os << _graph.id(n);
_blue_node_index.insert(std::make_pair(n, os.str()));
}
} else {
for (BlueNodeIt n(_graph); n != INVALID; ++n) {
std::string value = label->get(n);
_blue_node_index.insert(std::make_pair(n, value));
}
}
}
void writeEdges() {
_writer_bits::MapStorageBase<Edge>* label = 0;
for (typename EdgeMaps::iterator it = _edge_maps.begin();
it != _edge_maps.end(); ++it) {
if (it->first == "label") {
label = it->second;
break;
}
}
*_os << "@edges";
if (!_edges_caption.empty()) {
_writer_bits::writeToken(*_os << ' ', _edges_caption);
}
*_os << std::endl;
*_os << '\t' << '\t';
if (label == 0) {
*_os << "label" << '\t';
}
for (typename EdgeMaps::iterator it = _edge_maps.begin();
it != _edge_maps.end(); ++it) {
_writer_bits::writeToken(*_os, it->first) << '\t';
}
*_os << std::endl;
std::vector<Edge> edges;
for (EdgeIt n(_graph); n != INVALID; ++n) {
edges.push_back(n);
}
if (label == 0) {
IdMap<BGR, Edge> id_map(_graph);
_writer_bits::MapLess<IdMap<BGR, Edge> > id_less(id_map);
std::sort(edges.begin(), edges.end(), id_less);
} else {
label->sort(edges);
}
for (int i = 0; i < static_cast<int>(edges.size()); ++i) {
Edge e = edges[i];
_writer_bits::writeToken(*_os, _red_node_index.
find(_graph.redNode(e))->second);
*_os << '\t';
_writer_bits::writeToken(*_os, _blue_node_index.
find(_graph.blueNode(e))->second);
*_os << '\t';
if (label == 0) {
std::ostringstream os;
os << _graph.id(e);
_writer_bits::writeToken(*_os, os.str());
*_os << '\t';
_edge_index.insert(std::make_pair(e, os.str()));
}
for (typename EdgeMaps::iterator it = _edge_maps.begin();
it != _edge_maps.end(); ++it) {
std::string value = it->second->get(e);
_writer_bits::writeToken(*_os, value);
if (it->first == "label") {
_edge_index.insert(std::make_pair(e, value));
}
*_os << '\t';
}
*_os << std::endl;
}
}
void createEdgeIndex() {
_writer_bits::MapStorageBase<Edge>* label = 0;
for (typename EdgeMaps::iterator it = _edge_maps.begin();
it != _edge_maps.end(); ++it) {
if (it->first == "label") {
label = it->second;
break;
}
}
if (label == 0) {
for (EdgeIt e(_graph); e != INVALID; ++e) {
std::ostringstream os;
os << _graph.id(e);
_edge_index.insert(std::make_pair(e, os.str()));
}
} else {
for (EdgeIt e(_graph); e != INVALID; ++e) {
std::string value = label->get(e);
_edge_index.insert(std::make_pair(e, value));
}
}
}
void writeAttributes() {
if (_attributes.empty()) return;
*_os << "@attributes";
if (!_attributes_caption.empty()) {
_writer_bits::writeToken(*_os << ' ', _attributes_caption);
}
*_os << std::endl;
for (typename Attributes::iterator it = _attributes.begin();
it != _attributes.end(); ++it) {
_writer_bits::writeToken(*_os, it->first) << ' ';
_writer_bits::writeToken(*_os, it->second->get());
*_os << std::endl;
}
}
public:
/// \name Execution of the Writer
/// @{
/// \brief Start the batch processing
///
/// This function starts the batch processing.
void run() {
if (!_skip_nodes) {
writeRedNodes();
writeBlueNodes();
} else {
createRedNodeIndex();
createBlueNodeIndex();
}
if (!_skip_edges) {
writeEdges();
} else {
createEdgeIndex();
}
writeAttributes();
}
/// \brief Give back the stream of the writer
///
/// Give back the stream of the writer
std::ostream& ostream() {
return *_os;
}
/// @}
};
/// \ingroup lemon_io
///
/// \brief Return a \ref lemon::BpGraphWriter "BpGraphWriter" class
///
/// This function just returns a \ref lemon::BpGraphWriter
/// "BpGraphWriter" class.
///
/// With this function a bipartite graph can be write to a file or output
/// stream in \ref lgf-format "LGF" format with several maps and
/// attributes. For example, with the following code a bipartite
/// weighted matching problem can be written to the standard output,
/// i.e. a graph with a \e weight map on the edges:
///
///\code
///ListBpGraph graph;
///ListBpGraph::EdgeMap<int> weight(graph);
/// // Setting the weight map
///bpGraphWriter(graph, std::cout).
/// edgeMap("weight", weight).
/// run();
///\endcode
///
/// For a complete documentation, please see the
/// \ref lemon::BpGraphWriter "BpGraphWriter"
/// class documentation.
/// \warning Don't forget to put the \ref lemon::BpGraphWriter::run() "run()"
/// to the end of the parameter list.
/// \relates BpGraphWriter
/// \sa bpGraphWriter(const TBGR& graph, const std::string& fn)
/// \sa bpGraphWriter(const TBGR& graph, const char* fn)
template <typename TBGR>
BpGraphWriter<TBGR> bpGraphWriter(const TBGR& graph, std::ostream& os) {
BpGraphWriter<TBGR> tmp(graph, os);
return tmp;
}
/// \brief Return a \ref BpGraphWriter class
///
/// This function just returns a \ref BpGraphWriter class.
/// \relates BpGraphWriter
/// \sa graphWriter(const TBGR& graph, std::ostream& os)
template <typename TBGR>
BpGraphWriter<TBGR> bpGraphWriter(const TBGR& graph, const std::string& fn) {
BpGraphWriter<TBGR> tmp(graph, fn);
return tmp;
}
/// \brief Return a \ref BpGraphWriter class
///
/// This function just returns a \ref BpGraphWriter class.
/// \relates BpGraphWriter
/// \sa graphWriter(const TBGR& graph, std::ostream& os)
template <typename TBGR>
BpGraphWriter<TBGR> bpGraphWriter(const TBGR& graph, const char* fn) {
BpGraphWriter<TBGR> tmp(graph, fn);
return tmp;
}
class SectionWriter;
SectionWriter sectionWriter(std::istream& is);
SectionWriter sectionWriter(const std::string& fn);
SectionWriter sectionWriter(const char* fn);
/// \ingroup lemon_io
///
/// \brief Section writer class
///
/// In the \ref lgf-format "LGF" file extra sections can be placed,
/// which contain any data in arbitrary format. Such sections can be
/// written with this class. A writing rule can be added to the
/// class with two different functions. With the \c sectionLines()
/// function a generator can write the section line-by-line, while
/// with the \c sectionStream() member the section can be written to
/// an output stream.
class SectionWriter {
private:
std::ostream* _os;
bool local_os;
typedef std::vector<std::pair<std::string, _writer_bits::Section*> >
Sections;
Sections _sections;
public:
/// \brief Constructor
///
/// Construct a section writer, which writes to the given output
/// stream.
SectionWriter(std::ostream& os)
: _os(&os), local_os(false) {}
/// \brief Constructor
///
/// Construct a section writer, which writes into the given file.
SectionWriter(const std::string& fn)
: _os(new std::ofstream(fn.c_str())), local_os(true) {
if (!(*_os)) {
delete _os;
throw IoError("Cannot write file", fn);
}
}
/// \brief Constructor
///
/// Construct a section writer, which writes into the given file.
SectionWriter(const char* fn)
: _os(new std::ofstream(fn)), local_os(true) {
if (!(*_os)) {
delete _os;
throw IoError("Cannot write file", fn);
}
}
/// \brief Destructor
~SectionWriter() {
for (Sections::iterator it = _sections.begin();
it != _sections.end(); ++it) {
delete it->second;
}
if (local_os) {
delete _os;
}
}
private:
friend SectionWriter sectionWriter(std::ostream& os);
friend SectionWriter sectionWriter(const std::string& fn);
friend SectionWriter sectionWriter(const char* fn);
SectionWriter(SectionWriter& other)
: _os(other._os), local_os(other.local_os) {
other._os = 0;
other.local_os = false;
_sections.swap(other._sections);
}
SectionWriter& operator=(const SectionWriter&);
public:
/// \name Section Writers
/// @{
/// \brief Add a section writer with line oriented writing
///
/// The first parameter is the type descriptor of the section, the
/// second is a generator with std::string values. At the writing
/// process, the returned \c std::string will be written into the
/// output file until it is an empty string.
///
/// For example, an integer vector is written into a section.
///\code
/// @numbers
/// 12 45 23 78
/// 4 28 38 28
/// 23 6 16
///\endcode
///
/// The generator is implemented as a struct.
///\code
/// struct NumberSection {
/// std::vector<int>::const_iterator _it, _end;
/// NumberSection(const std::vector<int>& data)
/// : _it(data.begin()), _end(data.end()) {}
/// std::string operator()() {
/// int rem_in_line = 4;
/// std::ostringstream ls;
/// while (rem_in_line > 0 && _it != _end) {
/// ls << *(_it++) << ' ';
/// --rem_in_line;
/// }
/// return ls.str();
/// }
/// };
///
/// // ...
///
/// writer.sectionLines("numbers", NumberSection(vec));
///\endcode
template <typename Functor>
SectionWriter& sectionLines(const std::string& type, Functor functor) {
LEMON_ASSERT(!type.empty(), "Type is empty.");
_sections.push_back(std::make_pair(type,
new _writer_bits::LineSection<Functor>(functor)));
return *this;
}
/// \brief Add a section writer with stream oriented writing
///
/// The first parameter is the type of the section, the second is
/// a functor, which takes a \c std::ostream& parameter. The
/// functor writes the section to the output stream.
/// \warning The last line must be closed with end-line character.
template <typename Functor>
SectionWriter& sectionStream(const std::string& type, Functor functor) {
LEMON_ASSERT(!type.empty(), "Type is empty.");
_sections.push_back(std::make_pair(type,
new _writer_bits::StreamSection<Functor>(functor)));
return *this;
}
/// @}
public:
/// \name Execution of the Writer
/// @{
/// \brief Start the batch processing
///
/// This function starts the batch processing.
void run() {
LEMON_ASSERT(_os != 0, "This writer is assigned to an other writer");
for (Sections::iterator it = _sections.begin();
it != _sections.end(); ++it) {
(*_os) << '@' << it->first << std::endl;
it->second->process(*_os);
}
}
/// \brief Give back the stream of the writer
///
/// Returns the stream of the writer
std::ostream& ostream() {
return *_os;
}
/// @}
};
/// \ingroup lemon_io
///
/// \brief Return a \ref SectionWriter class
///
/// This function just returns a \ref SectionWriter class.
///
/// Please see SectionWriter documentation about the custom section
/// output.
///
/// \relates SectionWriter
/// \sa sectionWriter(const std::string& fn)
/// \sa sectionWriter(const char *fn)
inline SectionWriter sectionWriter(std::ostream& os) {
SectionWriter tmp(os);
return tmp;
}
/// \brief Return a \ref SectionWriter class
///
/// This function just returns a \ref SectionWriter class.
/// \relates SectionWriter
/// \sa sectionWriter(std::ostream& os)
inline SectionWriter sectionWriter(const std::string& fn) {
SectionWriter tmp(fn);
return tmp;
}
/// \brief Return a \ref SectionWriter class
///
/// This function just returns a \ref SectionWriter class.
/// \relates SectionWriter
/// \sa sectionWriter(std::ostream& os)
inline SectionWriter sectionWriter(const char* fn) {
SectionWriter tmp(fn);
return tmp;
}
}
#endif