diff options
Diffstat (limited to 'extern/quadriflow/3rd/lemon-1.3.1/lemon/lgf_writer.h')
-rw-r--r-- | extern/quadriflow/3rd/lemon-1.3.1/lemon/lgf_writer.h | 2687 |
1 files changed, 2687 insertions, 0 deletions
diff --git a/extern/quadriflow/3rd/lemon-1.3.1/lemon/lgf_writer.h b/extern/quadriflow/3rd/lemon-1.3.1/lemon/lgf_writer.h new file mode 100644 index 00000000000..0695287d518 --- /dev/null +++ b/extern/quadriflow/3rd/lemon-1.3.1/lemon/lgf_writer.h @@ -0,0 +1,2687 @@ +/* -*- 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 |