deba@1409: /* -*- C++ -*- deba@1409: * alpar@1956: * This file is a part of LEMON, a generic C++ optimization library alpar@1956: * alpar@1956: * Copyright (C) 2003-2006 alpar@1956: * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport deba@1409: * (Egervary Research Group on Combinatorial Optimization, EGRES). deba@1409: * deba@1409: * Permission to use, modify and distribute this software is granted deba@1409: * provided that this copyright notice appears in all copies. For deba@1409: * precise terms see the accompanying LICENSE file. deba@1409: * deba@1409: * This software is provided "AS IS" with no warranty of any kind, deba@1409: * express or implied, and with no claim as to its suitability for any deba@1409: * purpose. deba@1409: * deba@1409: */ deba@1409: deba@1409: ///\ingroup io_group deba@1409: ///\file deba@1409: ///\brief Lemon Format writer. deba@1409: deba@1409: #ifndef LEMON_LEMON_WRITER_H deba@1409: #define LEMON_LEMON_WRITER_H deba@1409: deba@1409: #include deba@1409: #include deba@1409: #include deba@1409: #include deba@1409: #include deba@1409: #include deba@1409: #include deba@1409: deba@1409: #include deba@1993: #include deba@1421: #include deba@1409: #include deba@1993: #include deba@1421: #include deba@1705: #include deba@1409: deba@1476: #include deba@1476: #include deba@1476: deba@1409: deba@1409: namespace lemon { deba@1409: deba@1476: namespace _writer_bits { deba@1476: deba@1476: template deba@1901: class ItemLabelWriter { deba@1476: public: deba@1476: deba@1901: bool isLabelWriter() { return true; } deba@1476: deba@1901: void writeLabel(std::ostream&, const Item&) {} deba@1476: deba@1901: template deba@1476: struct Constraints { deba@1476: void constraints() { deba@1901: bool b = writer.isLabelWriter(); deba@1476: ignore_unused_variable_warning(b); deba@1901: writer.writeLabel(os, item); deba@1476: } deba@1901: _ItemLabelWriter& writer; deba@1476: std::ostream& os; deba@1492: const Item& item; deba@1492: }; deba@1492: deba@1492: }; deba@1492: deba@1492: template deba@1492: class ItemWriter { deba@1492: public: deba@1492: deba@1492: void write(std::ostream&, const Item&) {} deba@1492: deba@1492: template deba@1492: struct Constraints { deba@1492: void constraints() { deba@1492: writer.write(os, item); deba@1492: } deba@1492: _ItemWriter& writer; deba@1492: std::ostream& os; deba@1492: const Item& item; deba@1476: }; deba@1476: deba@1476: }; deba@1476: deba@1705: template deba@1705: struct Ref { typedef const Map& Type; }; deba@1705: deba@1705: template deba@1705: class ForwardComposeMap { deba@1705: public: klao@1909: typedef typename Graph::UEdge Key; deba@1705: typedef typename Map::Value Value; deba@1705: deba@1705: ForwardComposeMap(const Graph& _graph, const Map& _map) deba@1705: : graph(_graph), map(_map) {} deba@1705: deba@1705: Value operator[](const Key& key) { deba@1705: return map[graph.direct(key, false)]; deba@1705: } deba@1705: deba@1705: private: deba@1705: typename Ref::Type map; deba@1705: const Graph& graph; deba@1705: }; deba@1705: deba@1705: template deba@1705: ForwardComposeMap deba@1705: forwardComposeMap(const Graph& graph, const Map& map) { deba@1705: return ForwardComposeMap(graph, map); deba@1705: } deba@1705: deba@1705: template deba@1705: class BackwardComposeMap { deba@1705: public: klao@1909: typedef typename Graph::UEdge Key; deba@1705: typedef typename Map::Value Value; deba@1705: deba@1705: BackwardComposeMap(const Graph& _graph, const Map& _map) deba@1705: : graph(_graph), map(_map) {} deba@1705: deba@1705: Value operator[](const Key& key) { deba@1705: return map[graph.direct(key, false)]; deba@1705: } deba@1705: deba@1705: private: deba@1705: typename Ref::Type map; deba@1705: const Graph& graph; deba@1705: }; deba@1705: deba@1705: template deba@1705: BackwardComposeMap deba@1705: backwardComposeMap(const Graph& graph, const Map& map) { deba@1705: return BackwardComposeMap(graph, map); deba@1705: } deba@1705: deba@1705: template deba@1705: struct Ref > { deba@1705: typedef ForwardComposeMap Type; deba@1705: }; deba@1705: deba@1705: template deba@1705: struct Ref > { deba@1705: typedef BackwardComposeMap Type; deba@1705: }; deba@1705: deba@1705: template deba@1705: struct Ref > { deba@1705: typedef XMap Type; deba@1705: }; deba@1705: template deba@1705: struct Ref > { deba@1705: typedef ConstXMap Type; deba@1705: }; deba@1705: deba@1705: template deba@1705: struct Ref > { deba@1705: typedef YMap Type; deba@1705: }; deba@1705: template deba@1705: struct Ref > { deba@1705: typedef ConstYMap Type; deba@1705: }; deba@1705: deba@1845: deba@1845: template deba@1845: class MapWriterBase { deba@1845: public: deba@1845: typedef _Item Item; deba@1845: deba@1845: virtual ~MapWriterBase() {} deba@1845: deba@1852: virtual void write(std::ostream& os, const Item& item) const = 0; deba@1845: }; deba@1845: deba@1845: deba@1845: template deba@1845: class MapWriter : public MapWriterBase<_Item> { deba@1845: public: deba@1845: typedef _Map Map; deba@1845: typedef _Writer Writer; deba@1845: typedef typename Writer::Value Value; deba@1845: typedef _Item Item; deba@1845: deba@1845: typename _writer_bits::Ref::Type map; deba@1845: Writer writer; deba@1845: deba@1845: MapWriter(const Map& _map, const Writer& _writer) deba@1845: : map(_map), writer(_writer) {} deba@1845: deba@1845: virtual ~MapWriter() {} deba@1845: deba@1852: virtual void write(std::ostream& os, const Item& item) const { deba@1845: Value value = map[item]; deba@1845: writer.write(os, value); deba@1845: } deba@1845: deba@1845: }; deba@1845: deba@1845: deba@1845: class ValueWriterBase { deba@1845: public: deba@1845: virtual ~ValueWriterBase() {} deba@1845: virtual void write(std::ostream&) = 0; deba@1845: }; deba@1845: deba@1845: template deba@1845: class ValueWriter : public ValueWriterBase { deba@1845: public: deba@1845: typedef _Value Value; deba@1845: typedef _Writer Writer; deba@1845: deba@1845: ValueWriter(const Value& _value, const Writer& _writer) deba@1845: : value(_value), writer(_writer) {} deba@1845: deba@1845: virtual void write(std::ostream& os) { deba@1845: writer.write(os, value); deba@1845: } deba@1845: private: deba@1845: const Value& value; deba@1845: Writer writer; deba@1845: }; deba@1845: deba@1845: deba@1845: template deba@1901: class LabelWriterBase { deba@1845: public: deba@1845: typedef _Item Item; deba@1901: virtual ~LabelWriterBase() {} deba@1845: virtual void write(std::ostream&, const Item&) const = 0; deba@1901: virtual bool isLabelWriter() const = 0; deba@1845: }; deba@1845: deba@1901: template deba@1901: class LabelWriter : public LabelWriterBase<_Item> { deba@1845: public: deba@1845: typedef _Item Item; deba@1901: typedef _BoxedLabelWriter BoxedLabelWriter; deba@1845: deba@1901: const BoxedLabelWriter& labelWriter; deba@1845: deba@1901: LabelWriter(const BoxedLabelWriter& _labelWriter) deba@1901: : labelWriter(_labelWriter) {} deba@1845: deba@1845: virtual void write(std::ostream& os, const Item& item) const { deba@1901: labelWriter.writeLabel(os, item); deba@1845: } deba@1845: deba@1901: virtual bool isLabelWriter() const { deba@1901: return labelWriter.isLabelWriter(); deba@1845: } deba@1845: }; deba@1845: deba@1476: } deba@1476: deba@1409: /// \ingroup io_group deba@1409: /// \brief Lemon Format writer class. deba@1409: /// deba@1409: /// The Lemon Format contains several sections. We do not want to deba@1409: /// determine what sections are in a lemon file we give only a framework deba@1409: /// to write a section oriented format. deba@1409: /// deba@1409: /// In the Lemon Format each section starts with a line contains a \c \@ deba@1409: /// character on the first not white space position. This line is the deba@1409: /// header line of the section. Each next lines belong to this section deba@1409: /// while it does not starts with \c \@ character. This line can start a deba@1409: /// new section or if it can close the file with the \c \@end line. deba@1409: /// The file format ignore the empty lines and it may contain comments deba@1409: /// started with a \c # character to the end of the line. deba@1409: /// deba@1409: /// The framework provides an abstract LemonWriter::SectionWriter class deba@1409: /// what defines the interface of a SectionWriter. The SectionWriter deba@1409: /// has the \c header() member function what gives back the header of the deba@1409: /// section. After that it will be called the \c write() member which deba@1409: /// should write the content of the section. deba@1409: /// deba@1409: /// \relates GraphWriter deba@1409: /// \relates NodeSetWriter deba@1409: /// \relates EdgeSetWriter deba@1409: /// \relates NodesWriter deba@1409: /// \relates EdgesWriter deba@1409: /// \relates AttributeWriter deba@1409: class LemonWriter { deba@1409: public: deba@1409: deba@1409: /// \brief Abstract base class for writing a section. deba@1409: /// deba@1409: /// This class has an \c header() member function what gives back deba@1409: /// the header line of the section. The \c write() member should deba@1409: /// write the content of the section to the stream. deba@1409: class SectionWriter { deba@1409: friend class LemonWriter; deba@1409: protected: deba@1409: /// \brief Constructor for SectionWriter. deba@1409: /// deba@1409: /// Constructor for SectionWriter. It attach this writer to deba@1409: /// the given LemonWriter. deba@1409: SectionWriter(LemonWriter& writer) { deba@1409: writer.attach(*this); deba@1409: } alpar@1494: alpar@1494: virtual ~SectionWriter() {} deba@1409: deba@1409: /// \brief The header of section. deba@1409: /// deba@1409: /// It gives back the header of the section. deba@1409: virtual std::string header() = 0; deba@1409: deba@1409: /// \brief Writer function of the section. deba@1409: /// deba@1409: /// Write the content of the section. deba@1409: virtual void write(std::ostream& os) = 0; deba@1409: }; deba@1409: deba@1409: /// \brief Constructor for LemonWriter. deba@1409: /// deba@1409: /// Constructor for LemonWriter which writes to the given stream. deba@1409: LemonWriter(std::ostream& _os) deba@1409: : os(&_os), own_os(false) {} deba@1409: deba@1409: /// \brief Constructor for LemonWriter. deba@1409: /// deba@1409: /// Constructor for LemonWriter which writes to the given file. deba@1409: LemonWriter(const std::string& filename) deba@1409: : os(0), own_os(true) { deba@1409: os = new std::ofstream(filename.c_str()); deba@1409: } deba@1409: deba@1409: /// \brief Desctructor for LemonWriter. deba@1409: /// deba@1409: /// Desctructor for LemonWriter. deba@1409: ~LemonWriter() { deba@1409: if (own_os) { deba@1409: delete os; deba@1409: } deba@1409: } deba@1409: deba@1409: private: deba@1409: LemonWriter(const LemonWriter&); deba@1409: void operator=(const LemonWriter&); deba@1409: deba@1409: void attach(SectionWriter& writer) { deba@1409: writers.push_back(&writer); deba@1409: } deba@1409: deba@1409: public: deba@1409: deba@1409: /// \brief Executes the LemonWriter. deba@1409: /// deba@1409: /// It executes the LemonWriter. deba@1409: void run() { deba@1409: SectionWriters::iterator it; deba@1409: for (it = writers.begin(); it != writers.end(); ++it) { deba@1409: *os << (*it)->header() << std::endl; deba@1409: (*it)->write(*os); deba@1409: } deba@1409: *os << "@end" << std::endl; deba@1409: } deba@1409: deba@1409: deba@1409: private: deba@1409: deba@1409: std::ostream* os; deba@1409: bool own_os; deba@1409: deba@1409: typedef std::vector SectionWriters; deba@1409: SectionWriters writers; deba@1409: deba@1409: }; deba@1409: deba@1409: /// \ingroup io_group deba@1409: /// \brief SectionWriter for writing a graph's nodeset. deba@1409: /// deba@1409: /// The lemon format can store multiple graph nodesets with several maps. deba@1901: /// The nodeset section's header line is \c \@nodeset \c nodeset_name, but deba@1901: /// the \c nodeset_name may be empty. deba@1409: /// deba@1409: /// The first line of the section contains the names of the maps separated deba@1409: /// with white spaces. Each next lines describes a node in the nodeset, and deba@1409: /// contains the mapped values for each map. deba@1409: /// deba@1901: /// If the nodeset contains an \c "label" named map then it will be regarded deba@1901: /// as label map. This map should contain only unique values and when the deba@1901: /// \c writeLabel() member will be called with a node it will write it's deba@1901: /// label. Otherwise if the \c _forceLabelMap constructor parameter is true deba@1901: /// then the label map will be the id in the graph. deba@1409: /// deba@1409: /// \relates LemonWriter deba@1409: template deba@1845: class NodeSetWriter : public LemonWriter::SectionWriter { deba@1845: typedef LemonWriter::SectionWriter Parent; deba@1409: public: deba@1409: deba@1409: typedef _Graph Graph; deba@1409: typedef _Traits Traits; deba@1429: typedef typename Graph::Node Node; deba@1409: deba@1409: /// \brief Constructor. deba@1409: /// deba@1409: /// Constructor for NodeSetWriter. It creates the NodeSetWriter and deba@1901: /// attach it into the given LemonWriter. If the \c _forceLabelMap deba@1901: /// parameter is true then the writer will write own label map when deba@1901: /// the user does not give "label" named map. deba@1409: NodeSetWriter(LemonWriter& _writer, const Graph& _graph, deba@1901: const std::string& _name = std::string(), deba@1901: bool _forceLabelMap = true) deba@1901: : Parent(_writer), labelMap(0), forceLabelMap(_forceLabelMap), deba@1901: graph(_graph), name(_name) {} deba@1409: deba@1409: /// \brief Destructor. deba@1409: /// deba@1409: /// Destructor for NodeSetWriter. deba@1409: virtual ~NodeSetWriter() { deba@1409: typename MapWriters::iterator it; deba@1409: for (it = writers.begin(); it != writers.end(); ++it) { deba@1409: delete it->second; deba@1409: } deba@1409: } deba@1409: deba@1409: private: deba@1409: NodeSetWriter(const NodeSetWriter&); deba@1409: void operator=(const NodeSetWriter&); deba@1409: deba@1409: public: deba@1409: deba@1409: /// \brief Add a new node map writer command for the writer. deba@1409: /// deba@1409: /// Add a new node map writer command for the writer. deba@1409: template deba@1421: NodeSetWriter& writeNodeMap(std::string name, const Map& map) { deba@1421: return writeNodeMap, Map>(name, map); deba@1409: } deba@1409: deba@1409: /// \brief Add a new node map writer command for the writer. deba@1409: /// deba@1409: /// Add a new node map writer command for the writer. deba@1409: template deba@1421: NodeSetWriter& writeNodeMap(std::string name, const Map& map, deba@1421: const Writer& writer = Writer()) { deba@1492: checkConcept, Map>(); deba@1492: checkConcept<_writer_bits::ItemWriter, Writer>(); deba@1409: writers.push_back( deba@1845: make_pair(name, new _writer_bits:: deba@1845: MapWriter(map, writer))); deba@1409: return *this; deba@1409: } deba@1409: deba@1409: protected: deba@1409: deba@1409: /// \brief The header of the section. deba@1409: /// deba@1409: /// It gives back the header of the section. deba@1409: virtual std::string header() { deba@1901: return "@nodeset " + name; deba@1409: } deba@1409: deba@1409: /// \brief Writer function of the section. deba@1409: /// deba@1409: /// Write the content of the section. deba@1409: virtual void write(std::ostream& os) { deba@1409: for (int i = 0; i < (int)writers.size(); ++i) { deba@1901: if (writers[i].first == "label" || (writers[i].first == "id" && labelMap == 0)) { deba@1901: labelMap = writers[i].second; deba@1901: forceLabelMap = false; deba@1409: break; deba@1409: } deba@1409: } deba@1901: if (forceLabelMap) { deba@1901: os << "label\t"; deba@1409: } deba@1409: for (int i = 0; i < (int)writers.size(); ++i) { deba@1409: os << writers[i].first << '\t'; deba@1409: } deba@1409: os << std::endl; deba@1409: for (typename Graph::NodeIt it(graph); it != INVALID; ++it) { deba@1901: if (forceLabelMap) { deba@1409: os << graph.id(it) << '\t'; deba@1409: } deba@1409: for (int i = 0; i < (int)writers.size(); ++i) { deba@1409: writers[i].second->write(os, it); deba@1409: os << '\t'; deba@1409: } deba@1409: os << std::endl; deba@1409: } deba@1409: } deba@1409: deba@1409: public: deba@1409: deba@1901: /// \brief Returns true if the nodeset can write the labels of the nodes. deba@1409: /// deba@1901: /// Returns true if the nodeset can write the labels of the nodes. deba@1901: /// It is possible only if an "label" named map was written or the deba@1901: /// \c _forceLabelMap constructor parameter was true. deba@1901: bool isLabelWriter() const { deba@1901: return labelMap != 0 || forceLabelMap; deba@1409: } deba@1409: deba@1901: /// \brief Write the label of the given node. deba@1409: /// deba@1901: /// It writes the label of the given node. If there was written an "label" deba@1409: /// named map then it will write the map value belongs to the node. deba@1901: /// Otherwise if the \c forceLabel parameter was true it will write deba@1901: /// its label in the graph. deba@1901: void writeLabel(std::ostream& os, const Node& item) const { deba@1901: if (forceLabelMap) { deba@1409: os << graph.id(item); deba@1409: } else { deba@1901: labelMap->write(os, item); deba@1409: } deba@1409: } deba@1409: deba@1409: private: deba@1409: deba@1845: typedef std::vector*> > MapWriters; deba@1409: MapWriters writers; deba@1409: deba@1901: _writer_bits::MapWriterBase* labelMap; deba@1901: bool forceLabelMap; deba@1409: deba@1705: const Graph& graph; deba@1901: std::string name; deba@1409: deba@1409: }; deba@1409: deba@1409: /// \ingroup io_group deba@1421: /// \brief SectionWriter for writing a graph's edgesets. deba@1409: /// deba@1421: /// The lemon format can store multiple graph edgesets with several maps. deba@1901: /// The edgeset section's header line is \c \@edgeset \c edgeset_name, but deba@1901: /// the \c edgeset_name may be empty. deba@1409: /// deba@1409: /// The first line of the section contains the names of the maps separated deba@1409: /// with white spaces. Each next lines describes a edge in the edgeset. The deba@1901: /// line contains the source and the target nodes' label and the mapped deba@1409: /// values for each map. deba@1409: /// deba@1901: /// If the edgeset contains an \c "label" named map then it will be regarded deba@1901: /// as label map. This map should contain only unique values and when the deba@1901: /// \c writeLabel() member will be called with an edge it will write it's deba@1901: /// label. Otherwise if the \c _forceLabelMap constructor parameter is true deba@1901: /// then the label map will be the id in the graph. deba@1409: /// deba@1901: /// The edgeset writer needs a node label writer to identify which nodes deba@1901: /// have to be connected. If a NodeSetWriter can write the nodes' label, deba@1409: /// it will be able to use with this class. deba@1409: /// deba@1409: /// \relates LemonWriter deba@1409: template deba@1845: class EdgeSetWriter : public LemonWriter::SectionWriter { deba@1845: typedef LemonWriter::SectionWriter Parent; deba@1409: public: deba@1409: deba@1409: typedef _Graph Graph; deba@1409: typedef _Traits Traits; deba@1429: typedef typename Graph::Node Node; deba@1429: typedef typename Graph::Edge Edge; deba@1409: deba@1409: /// \brief Constructor. deba@1409: /// deba@1409: /// Constructor for EdgeSetWriter. It creates the EdgeSetWriter and deba@1901: /// attach it into the given LemonWriter. It will write node labels by deba@1901: /// the \c _nodeLabelWriter. If the \c _forceLabelMap parameter is true deba@1901: /// then the writer will write own label map if the user does not give deba@1901: /// "label" named map. deba@1901: template deba@1409: EdgeSetWriter(LemonWriter& _writer, const Graph& _graph, deba@1901: const NodeLabelWriter& _nodeLabelWriter, deba@1901: const std::string& _name = std::string(), deba@1901: bool _forceLabelMap = true) deba@1901: : Parent(_writer), labelMap(0), forceLabelMap(_forceLabelMap), deba@1901: graph(_graph), name(_name) { deba@1901: checkConcept<_writer_bits::ItemLabelWriter, NodeLabelWriter>(); deba@1901: nodeLabelWriter.reset(new _writer_bits:: deba@1901: LabelWriter(_nodeLabelWriter)); deba@1476: } deba@1409: deba@1409: /// \brief Destructor. deba@1409: /// deba@1409: /// Destructor for EdgeSetWriter. deba@1409: virtual ~EdgeSetWriter() { deba@1409: typename MapWriters::iterator it; deba@1409: for (it = writers.begin(); it != writers.end(); ++it) { deba@1409: delete it->second; deba@1409: } deba@1409: } deba@1409: deba@1409: private: deba@1409: EdgeSetWriter(const EdgeSetWriter&); deba@1409: void operator=(const EdgeSetWriter&); deba@1409: deba@1409: public: deba@1409: deba@1421: /// \brief Add a new edge map writer command for the writer. deba@1409: /// deba@1421: /// Add a new edge map writer command for the writer. deba@1409: template deba@1421: EdgeSetWriter& writeEdgeMap(std::string name, const Map& map) { deba@1421: return writeEdgeMap, Map>(name, map); deba@1409: } deba@1409: deba@1421: /// \brief Add a new edge map writer command for the writer. deba@1409: /// deba@1421: /// Add a new edge map writer command for the writer. deba@1409: template deba@1421: EdgeSetWriter& writeEdgeMap(std::string name, const Map& map, deba@1421: const Writer& writer = Writer()) { deba@1492: checkConcept, Map>(); deba@1492: checkConcept<_writer_bits::ItemWriter, Writer>(); deba@1409: writers.push_back( deba@1845: make_pair(name, new _writer_bits:: deba@1845: MapWriter(map, writer))); deba@1409: return *this; deba@1409: } deba@1409: deba@1409: protected: deba@1409: deba@1409: /// \brief The header of the section. deba@1409: /// deba@1409: /// It gives back the header of the section. deba@1409: virtual std::string header() { deba@1901: return "@edgeset " + name; deba@1409: } deba@1409: deba@1409: /// \brief Writer function of the section. deba@1409: /// deba@1409: /// Write the content of the section. deba@1409: virtual void write(std::ostream& os) { deba@1901: if (!nodeLabelWriter->isLabelWriter()) { deba@1901: throw DataFormatError("Cannot find nodeset or label map"); deba@1476: } deba@1409: for (int i = 0; i < (int)writers.size(); ++i) { deba@1901: if (writers[i].first == "label" || (writers[i].first == "id" && labelMap == 0)) { deba@1901: labelMap = writers[i].second; deba@1901: forceLabelMap = false; deba@1409: break; deba@1409: } deba@1409: } deba@1409: os << "\t\t"; deba@1901: if (forceLabelMap) { deba@1901: os << "label\t"; deba@1409: } deba@1409: for (int i = 0; i < (int)writers.size(); ++i) { deba@1409: os << writers[i].first << '\t'; deba@1409: } deba@1409: os << std::endl; deba@1409: for (typename Graph::EdgeIt it(graph); it != INVALID; ++it) { deba@1901: nodeLabelWriter->write(os, graph.source(it)); deba@1409: os << '\t'; deba@1901: nodeLabelWriter->write(os, graph.target(it)); deba@1409: os << '\t'; deba@1901: if (forceLabelMap) { deba@1409: os << graph.id(it) << '\t'; deba@1409: } deba@1409: for (int i = 0; i < (int)writers.size(); ++i) { deba@1409: writers[i].second->write(os, it); deba@1409: os << '\t'; deba@1409: } deba@1409: os << std::endl; deba@1409: } deba@1409: } deba@1409: deba@1409: public: deba@1409: deba@1901: /// \brief Returns true if the edgeset can write the labels of the edges. deba@1409: /// deba@1901: /// Returns true if the edgeset can write the labels of the edges. deba@1901: /// It is possible only if an "label" named map was written or the deba@1901: /// \c _forceLabelMap constructor parameter was true. deba@1901: bool isLabelWriter() const { deba@1901: return forceLabelMap || labelMap != 0; deba@1409: } deba@1409: deba@1901: /// \brief Write the label of the given edge. deba@1409: /// deba@1901: /// It writes the label of the given edge. If there was written an "label" deba@1409: /// named map then it will write the map value belongs to the edge. deba@1901: /// Otherwise if the \c forceLabel parameter was true it will write deba@1901: /// its label in the graph. deba@1901: void writeLabel(std::ostream& os, const Edge& item) const { deba@1901: if (forceLabelMap) { deba@1409: os << graph.id(item); deba@1409: } else { deba@1901: labelMap->write(os, item); deba@1409: } deba@1409: } deba@1409: deba@1409: private: deba@1409: deba@1845: typedef std::vector*> > MapWriters; deba@1409: MapWriters writers; deba@1409: deba@1901: _writer_bits::MapWriterBase* labelMap; deba@1901: bool forceLabelMap; deba@1409: deba@1705: const Graph& graph; deba@1901: std::string name; deba@1421: deba@1901: std::auto_ptr<_writer_bits::LabelWriterBase > nodeLabelWriter; deba@1421: }; deba@1421: deba@1421: /// \ingroup io_group deba@1421: /// \brief SectionWriter for writing a undirected edgeset. deba@1421: /// deba@1421: /// The lemon format can store multiple undirected edgesets with several klao@1909: /// maps. The undirected edgeset section's header line is \c \@uedgeset klao@1909: /// \c uedgeset_name, but the \c uedgeset_name may be empty. deba@1421: /// deba@1421: /// The first line of the section contains the names of the maps separated deba@1421: /// with white spaces. Each next lines describes an undirected edge in the deba@1901: /// edgeset. The line contains the two connected nodes' label and the mapped deba@1421: /// values for each undirected map. deba@1421: /// deba@1421: /// The section can handle the directed as a syntactical sugar. Two deba@1421: /// undirected edge map describes one directed edge map. This two maps deba@1421: /// are the forward map and the backward map and the names of this map deba@1421: /// is near the same just with a prefix \c '+' or \c '-' character deba@1421: /// difference. deba@1421: /// deba@1901: /// If the edgeset contains an \c "label" named map then it will be regarded deba@1901: /// as label map. This map should contain only unique values and when the deba@1901: /// \c writeLabel() member will be called with an undirected edge it will deba@1901: /// write it's label. Otherwise if the \c _forceLabelMap constructor deba@1901: /// parameter is true then the label map will be the id in the graph. deba@1421: /// deba@1901: /// The undirected edgeset writer needs a node label writer to identify deba@1421: /// which nodes have to be connected. If a NodeSetWriter can write the deba@1901: /// nodes' label, it will be able to use with this class. deba@1421: /// deba@1421: /// \relates LemonWriter deba@1421: template klao@1909: class UEdgeSetWriter : public LemonWriter::SectionWriter { deba@1845: typedef LemonWriter::SectionWriter Parent; deba@1421: public: deba@1421: deba@1421: typedef _Graph Graph; deba@1421: typedef _Traits Traits; deba@1429: typedef typename Graph::Node Node; deba@1429: typedef typename Graph::Edge Edge; klao@1909: typedef typename Graph::UEdge UEdge; deba@1421: deba@1421: /// \brief Constructor. deba@1421: /// klao@1909: /// Constructor for UEdgeSetWriter. It creates the UEdgeSetWriter deba@1901: /// and attach it into the given LemonWriter. It will write node labels by deba@1901: /// the \c _nodeLabelWriter. If the \c _forceLabelMap parameter is true deba@1901: /// then the writer will write own label map if the user does not give deba@1901: /// "label" named map. deba@1901: template klao@1909: UEdgeSetWriter(LemonWriter& _writer, const Graph& _graph, deba@1901: const NodeLabelWriter& _nodeLabelWriter, deba@1901: const std::string& _name = std::string(), deba@1901: bool _forceLabelMap = true) deba@1901: : Parent(_writer), labelMap(0), forceLabelMap(_forceLabelMap), deba@1901: graph(_graph), name(_name) { deba@1901: checkConcept<_writer_bits::ItemLabelWriter, NodeLabelWriter>(); deba@1901: nodeLabelWriter.reset(new _writer_bits:: deba@1901: LabelWriter(_nodeLabelWriter)); deba@1476: } deba@1421: deba@1421: /// \brief Destructor. deba@1421: /// klao@1909: /// Destructor for UEdgeSetWriter. klao@1909: virtual ~UEdgeSetWriter() { deba@1421: typename MapWriters::iterator it; deba@1421: for (it = writers.begin(); it != writers.end(); ++it) { deba@1421: delete it->second; deba@1421: } deba@1421: } deba@1421: deba@1421: private: klao@1909: UEdgeSetWriter(const UEdgeSetWriter&); klao@1909: void operator=(const UEdgeSetWriter&); deba@1421: deba@1421: public: deba@1421: deba@1421: /// \brief Add a new undirected edge map writer command for the writer. deba@1421: /// deba@1421: /// Add a new undirected map writer command for the writer. deba@1421: template klao@1909: UEdgeSetWriter& writeUEdgeMap(std::string name, const Map& map) { klao@1909: return writeUEdgeMap, Map>(name, map); deba@1421: } deba@1421: deba@1421: /// \brief Add a new undirected map writer command for the writer. deba@1421: /// deba@1421: /// Add a new undirected map writer command for the writer. deba@1421: template klao@1909: UEdgeSetWriter& writeUEdgeMap(std::string name, const Map& map, deba@1421: const Writer& writer = Writer()) { klao@1909: checkConcept, Map>(); deba@1492: checkConcept<_writer_bits::ItemWriter, Writer>(); deba@1421: writers.push_back( deba@1845: make_pair(name, new _writer_bits:: klao@1909: MapWriter(map, writer))); deba@1421: return *this; deba@1421: } deba@1421: deba@1421: /// \brief Add a new directed edge map writer command for the writer. deba@1421: /// deba@1421: /// Add a new directed map writer command for the writer. deba@1421: template klao@1909: UEdgeSetWriter& writeEdgeMap(std::string name, const Map& map) { deba@1492: return writeEdgeMap, Map>(name, map); deba@1421: } deba@1421: deba@1421: /// \brief Add a new directed map writer command for the writer. deba@1421: /// deba@1421: /// Add a new directed map writer command for the writer. deba@1421: template klao@1909: UEdgeSetWriter& writeEdgeMap(std::string name, const Map& map, deba@1421: const Writer& writer = Writer()) { deba@1492: checkConcept, Map>(); deba@1492: checkConcept<_writer_bits::ItemWriter, Writer>(); klao@1909: writeUEdge("+" + name, deba@1705: _writer_bits::forwardComposeMap(graph, map), writer); klao@1909: writeUEdge("-" + name, deba@1705: _writer_bits::backwardComposeMap(graph, map), writer); deba@1421: return *this; deba@1421: } deba@1421: deba@1421: protected: deba@1421: deba@1421: /// \brief The header of the section. deba@1421: /// deba@1421: /// It gives back the header of the section. deba@1421: virtual std::string header() { klao@1909: return "@uedgeset " + name; deba@1421: } deba@1421: deba@1421: /// \brief Writer function of the section. deba@1421: /// deba@1421: /// Write the content of the section. deba@1421: virtual void write(std::ostream& os) { deba@1901: if (!nodeLabelWriter->isLabelWriter()) { deba@1901: throw DataFormatError("Cannot find nodeset or label map"); deba@1476: } deba@1421: for (int i = 0; i < (int)writers.size(); ++i) { deba@1901: if (writers[i].first == "label") { deba@1901: labelMap = writers[i].second; deba@1901: forceLabelMap = false; deba@1421: break; deba@1421: } deba@1421: } deba@1421: os << "\t\t"; deba@1901: if (forceLabelMap) { deba@1901: os << "label\t"; deba@1421: } deba@1421: for (int i = 0; i < (int)writers.size(); ++i) { deba@1421: os << writers[i].first << '\t'; deba@1421: } deba@1421: os << std::endl; klao@1909: for (typename Graph::UEdgeIt it(graph); it != INVALID; ++it) { deba@1901: nodeLabelWriter->write(os, graph.source(it)); deba@1421: os << '\t'; deba@1901: nodeLabelWriter->write(os, graph.target(it)); deba@1421: os << '\t'; deba@1901: if (forceLabelMap) { deba@1421: os << graph.id(it) << '\t'; deba@1421: } deba@1421: for (int i = 0; i < (int)writers.size(); ++i) { deba@1421: writers[i].second->write(os, it); deba@1421: os << '\t'; deba@1421: } deba@1421: os << std::endl; deba@1421: } deba@1421: } deba@1421: deba@1421: public: deba@1421: deba@1901: /// \brief Returns true if the undirected edgeset can write the labels of deba@1421: /// the edges. deba@1421: /// deba@1901: /// Returns true if the undirected edgeset can write the labels of the deba@1901: /// undirected edges. It is possible only if an "label" named map was deba@1901: /// written or the \c _forceLabelMap constructor parameter was true. deba@1901: bool isLabelWriter() const { deba@1901: return forceLabelMap || labelMap != 0; deba@1421: } deba@1421: deba@1901: /// \brief Write the label of the given undirected edge. deba@1421: /// deba@1901: /// It writes the label of the given undirected edge. If there was written deba@1901: /// an "label" named map then it will write the map value belongs to the deba@1901: /// undirected edge. Otherwise if the \c forceLabel parameter was true it deba@1421: /// will write its id in the graph. klao@1909: void writeLabel(std::ostream& os, const UEdge& item) const { deba@1901: if (forceLabelMap) { deba@1429: os << graph.id(item); deba@1429: } else { deba@1901: labelMap->write(os, item); deba@1429: } deba@1429: } deba@1429: deba@1901: /// \brief Write the label of the given edge. deba@1429: /// deba@1901: /// It writes the label of the given edge. If there was written deba@1901: /// an "label" named map then it will write the map value belongs to the deba@1901: /// edge. Otherwise if the \c forceLabel parameter was true it deba@1429: /// will write its id in the graph. If the edge is forward map deba@1429: /// then its prefix character is \c '+' elsewhere \c '-'. deba@1901: void writeLabel(std::ostream& os, const Edge& item) const { deba@1690: if (graph.direction(item)) { deba@1429: os << "+ "; deba@1429: } else { deba@1429: os << "- "; deba@1429: } deba@1901: if (forceLabelMap) { deba@1421: os << graph.id(item); deba@1421: } else { deba@1901: labelMap->write(os, item); deba@1421: } deba@1421: } deba@1421: deba@1421: private: deba@1421: deba@1845: typedef std::vector*> > MapWriters; deba@1421: MapWriters writers; deba@1421: klao@1909: _writer_bits::MapWriterBase* labelMap; deba@1901: bool forceLabelMap; deba@1421: deba@1705: const Graph& graph; deba@1901: std::string name; deba@1409: deba@1901: std::auto_ptr<_writer_bits::LabelWriterBase > nodeLabelWriter; deba@1409: }; deba@1409: deba@1409: /// \ingroup io_group deba@1901: /// \brief SectionWriter for writing named nodes. deba@1409: /// deba@1901: /// The nodes section's header line is \c \@nodes \c nodes_name, but the deba@1901: /// \c nodes_name may be empty. deba@1409: /// deba@1901: /// Each line in the section contains the name of the node and deba@1901: /// then the node label. deba@1409: /// deba@1409: /// \relates LemonWriter deba@1409: template deba@1845: class NodeWriter : public LemonWriter::SectionWriter { deba@1845: typedef LemonWriter::SectionWriter Parent; deba@1409: typedef _Graph Graph; deba@1429: typedef typename Graph::Node Node; deba@1409: public: deba@1409: deba@1409: /// \brief Constructor. deba@1409: /// deba@1409: /// Constructor for NodeWriter. It creates the NodeWriter and deba@1901: /// attach it into the given LemonWriter. The given \c _LabelWriter deba@1901: /// will write the nodes' label what can be a nodeset writer. deba@1901: template deba@1901: NodeWriter(LemonWriter& _writer, const _LabelWriter& _labelWriter, deba@1901: const std::string& _name = std::string()) deba@1901: : Parent(_writer), name(_name) { deba@1901: checkConcept<_writer_bits::ItemLabelWriter, _LabelWriter>(); deba@1901: labelWriter.reset(new _writer_bits::LabelWriter deba@1901: (_labelWriter)); deba@1476: } deba@1476: deba@1409: deba@1409: /// \brief Destructor. deba@1409: /// deba@1409: /// Destructor for NodeWriter. deba@1409: virtual ~NodeWriter() {} deba@1409: deba@1409: private: deba@1409: NodeWriter(const NodeWriter&); deba@1409: void operator=(const NodeWriter&); deba@1409: deba@1409: public: deba@1409: deba@1409: /// \brief Add a node writer command for the NodeWriter. deba@1409: /// deba@1409: /// Add a node writer command for the NodeWriter. deba@1429: void writeNode(const std::string& name, const Node& item) { deba@1409: writers.push_back(make_pair(name, &item)); deba@1409: } deba@1409: deba@1409: protected: deba@1409: deba@1901: /// \brief The header of the section. deba@1409: /// deba@1901: /// It gives back the header of the section. deba@1409: virtual std::string header() { deba@1901: return "@nodes " + name; deba@1409: } deba@1409: deba@1409: /// \brief Writer function of the section. deba@1409: /// deba@1409: /// Write the content of the section. deba@1409: virtual void write(std::ostream& os) { deba@1901: if (!labelWriter->isLabelWriter()) { deba@1901: throw DataFormatError("Cannot find nodeset or label map"); deba@1476: } deba@1409: for (int i = 0; i < (int)writers.size(); ++i) { deba@1409: os << writers[i].first << ' '; deba@1901: labelWriter->write(os, *(writers[i].second)); deba@1409: os << std::endl; deba@1409: } deba@1409: } deba@1409: deba@1409: private: deba@1409: deba@1901: std::string name; deba@1409: deba@1429: typedef std::vector > NodeWriters; deba@1429: NodeWriters writers; deba@1901: std::auto_ptr<_writer_bits::LabelWriterBase > labelWriter; deba@1409: }; deba@1409: deba@1409: /// \ingroup io_group deba@1901: /// \brief SectionWriter for writing named edges. deba@1409: /// deba@1901: /// The edges section's header line is \c \@edges \c edges_name, but the deba@1901: /// \c edges_name may be empty. deba@1409: /// deba@1901: /// Each line in the section contains the name of the edge and deba@1901: /// then the edge label. deba@1409: /// deba@1409: /// \relates LemonWriter deba@1409: template deba@1845: class EdgeWriter : public LemonWriter::SectionWriter { deba@1845: typedef LemonWriter::SectionWriter Parent; deba@1409: typedef _Graph Graph; deba@1429: typedef typename Graph::Edge Edge; deba@1409: public: deba@1409: deba@1409: /// \brief Constructor. deba@1409: /// deba@1409: /// Constructor for EdgeWriter. It creates the EdgeWriter and deba@1901: /// attach it into the given LemonWriter. The given \c _LabelWriter deba@1901: /// will write the edges' label what can be a edgeset writer. deba@1901: template deba@1901: EdgeWriter(LemonWriter& _writer, const _LabelWriter& _labelWriter, deba@1901: const std::string& _name = std::string()) deba@1901: : Parent(_writer), name(_name) { deba@1901: checkConcept<_writer_bits::ItemLabelWriter, _LabelWriter>(); deba@1901: labelWriter.reset(new _writer_bits::LabelWriter(_labelWriter)); deba@1476: } deba@1409: deba@1409: /// \brief Destructor. deba@1409: /// deba@1409: /// Destructor for EdgeWriter. deba@1409: virtual ~EdgeWriter() {} deba@1409: private: deba@1409: EdgeWriter(const EdgeWriter&); deba@1409: void operator=(const EdgeWriter&); deba@1409: deba@1409: public: deba@1409: deba@1421: /// \brief Add an edge writer command for the EdgeWriter. deba@1409: /// deba@1421: /// Add an edge writer command for the EdgeWriter. deba@1429: void writeEdge(const std::string& name, const Edge& item) { deba@1409: writers.push_back(make_pair(name, &item)); deba@1409: } deba@1409: deba@1409: protected: deba@1409: deba@1901: /// \brief The header of the section. deba@1409: /// deba@1901: /// It gives back the header of the section. deba@1421: virtual std::string header() { deba@1901: return "@edges " + name; deba@1421: } deba@1421: deba@1421: /// \brief Writer function of the section. deba@1421: /// deba@1421: /// Write the content of the section. deba@1421: virtual void write(std::ostream& os) { deba@1901: if (!labelWriter->isLabelWriter()) { deba@1901: throw DataFormatError("Cannot find edgeset or label map"); deba@1476: } deba@1421: for (int i = 0; i < (int)writers.size(); ++i) { deba@1421: os << writers[i].first << ' '; deba@1901: labelWriter->write(os, *(writers[i].second)); deba@1421: os << std::endl; deba@1421: } deba@1421: } deba@1421: deba@1421: private: deba@1421: deba@1901: std::string name; deba@1421: deba@1429: typedef std::vector > EdgeWriters; deba@1429: EdgeWriters writers; deba@1421: deba@1901: std::auto_ptr<_writer_bits::LabelWriterBase > labelWriter; deba@1421: }; deba@1421: deba@1421: /// \ingroup io_group deba@1901: /// \brief SectionWriter for writing named undirected edges. deba@1421: /// klao@1909: /// The undirected edges section's header line is \c \@uedges klao@1909: /// \c uedges_name, but the \c uedges_name may be empty. deba@1421: /// deba@1901: /// Each line in the section contains the name of the undirected edge and deba@1901: /// then the undirected edge label. deba@1421: /// deba@1421: /// \relates LemonWriter deba@1421: template klao@1909: class UEdgeWriter : public LemonWriter::SectionWriter { deba@1845: typedef LemonWriter::SectionWriter Parent; deba@1421: typedef _Graph Graph; deba@1429: typedef typename Graph::Node Node; deba@1429: typedef typename Graph::Edge Edge; klao@1909: typedef typename Graph::UEdge UEdge; deba@1421: public: deba@1421: deba@1421: /// \brief Constructor. deba@1421: /// klao@1909: /// Constructor for UEdgeWriter. It creates the UEdgeWriter and deba@1901: /// attach it into the given LemonWriter. The given \c _LabelWriter deba@1901: /// will write the undirected edges' label what can be an undirected deba@1421: /// edgeset writer. deba@1901: template klao@1909: UEdgeWriter(LemonWriter& _writer, const _LabelWriter& _labelWriter, deba@1901: const std::string& _name = std::string()) deba@1901: : Parent(_writer), name(_name) { deba@1901: checkConcept<_writer_bits::ItemLabelWriter, _LabelWriter>(); klao@1909: checkConcept<_writer_bits::ItemLabelWriter, _LabelWriter>(); klao@1909: uEdgeLabelWriter.reset(new _writer_bits:: klao@1909: LabelWriter(_labelWriter)); deba@1901: edgeLabelWriter.reset(new _writer_bits:: deba@1901: LabelWriter(_labelWriter)); deba@1476: } deba@1421: deba@1421: /// \brief Destructor. deba@1421: /// klao@1909: /// Destructor for UEdgeWriter. klao@1909: virtual ~UEdgeWriter() {} deba@1421: private: klao@1909: UEdgeWriter(const UEdgeWriter&); klao@1909: void operator=(const UEdgeWriter&); deba@1421: deba@1421: public: deba@1421: klao@1909: /// \brief Add an edge writer command for the UEdgeWriter. deba@1429: /// klao@1909: /// Add an edge writer command for the UEdgeWriter. deba@1429: void writeEdge(const std::string& name, const Edge& item) { deba@1429: edgeWriters.push_back(make_pair(name, &item)); deba@1429: } deba@1429: klao@1909: /// \brief Add an undirected edge writer command for the UEdgeWriter. deba@1421: /// klao@1909: /// Add an undirected edge writer command for the UEdgeWriter. klao@1909: void writeUEdge(const std::string& name, const UEdge& item) { klao@1909: uEdgeWriters.push_back(make_pair(name, &item)); deba@1421: } deba@1421: deba@1421: protected: deba@1421: deba@1901: /// \brief The header of the section. deba@1421: /// deba@1901: /// It gives back the header of the section. deba@1409: virtual std::string header() { klao@1909: return "@uedges " + name; deba@1409: } deba@1409: deba@1409: /// \brief Writer function of the section. deba@1409: /// deba@1409: /// Write the content of the section. deba@1409: virtual void write(std::ostream& os) { deba@1901: if (!edgeLabelWriter->isLabelWriter()) { deba@1901: throw DataFormatError("Cannot find undirected edgeset or label map"); deba@1476: } klao@1909: if (!uEdgeLabelWriter->isLabelWriter()) { deba@1901: throw DataFormatError("Cannot find undirected edgeset or label map"); deba@1476: } klao@1909: for (int i = 0; i < (int)uEdgeWriters.size(); ++i) { klao@1909: os << uEdgeWriters[i].first << ' '; klao@1909: uEdgeLabelWriter->write(os, *(uEdgeWriters[i].second)); deba@1429: os << std::endl; deba@1429: } deba@1429: for (int i = 0; i < (int)edgeWriters.size(); ++i) { deba@1429: os << edgeWriters[i].first << ' '; deba@1901: edgeLabelWriter->write(os, *(edgeWriters[i].second)); deba@1409: os << std::endl; deba@1409: } deba@1409: } deba@1409: deba@1409: private: deba@1409: deba@1901: std::string name; deba@1409: deba@1429: typedef std::vector > UEdgeWriters; klao@1909: UEdgeWriters uEdgeWriters; klao@1909: std::auto_ptr<_writer_bits::LabelWriterBase > uEdgeLabelWriter; deba@1409: deba@1429: typedef std::vector > EdgeWriters; deba@1429: EdgeWriters edgeWriters; deba@1901: std::auto_ptr<_writer_bits::LabelWriterBase > edgeLabelWriter; deba@1429: deba@1409: }; deba@1409: deba@1409: /// \ingroup io_group deba@1409: /// \brief SectionWriter for attributes. deba@1409: /// deba@1409: /// The lemon format can store multiple attribute set. Each set has deba@1901: /// the header line \c \@attributes \c attributes_name, but the deba@1901: /// attributeset_name may be empty. deba@1409: /// deba@1409: /// The attributeset section contains several lines. Each of them starts deba@1409: /// with the name of attribute and then the value. deba@1409: /// deba@1409: /// \relates LemonWriter deba@1409: template deba@1845: class AttributeWriter : public LemonWriter::SectionWriter { deba@1845: typedef LemonWriter::SectionWriter Parent; deba@1409: typedef _Traits Traits; deba@1409: public: deba@1409: /// \brief Constructor. deba@1409: /// deba@1409: /// Constructor for AttributeWriter. It creates the AttributeWriter and deba@1409: /// attach it into the given LemonWriter. deba@1409: AttributeWriter(LemonWriter& _writer, deba@1901: const std::string& _name = std::string()) deba@1901: : Parent(_writer), name(_name) {} deba@1409: deba@1409: /// \brief Destructor. deba@1409: /// deba@1409: /// Destructor for AttributeWriter. deba@1409: virtual ~AttributeWriter() { deba@1409: typename Writers::iterator it; deba@1409: for (it = writers.begin(); it != writers.end(); ++it) { deba@1409: delete it->second; deba@1409: } deba@1409: } deba@1409: deba@1409: private: deba@1409: AttributeWriter(const AttributeWriter&); deba@1409: void operator=(AttributeWriter&); deba@1409: deba@1409: public: deba@1409: /// \brief Add an attribute writer command for the writer. deba@1409: /// deba@1409: /// Add an attribute writer command for the writer. deba@1409: template deba@1901: AttributeWriter& writeAttribute(const std::string& name, deba@1409: const Value& value) { deba@1409: return deba@1901: writeAttribute >(name, value); deba@1409: } deba@1409: deba@1409: /// \brief Add an attribute writer command for the writer. deba@1409: /// deba@1409: /// Add an attribute writer command for the writer. deba@1409: template deba@1409: AttributeWriter& writeAttribute(const std::string& name, deba@1409: const Value& value, deba@1409: const Writer& writer = Writer()) { deba@1492: checkConcept<_writer_bits::ItemWriter, Writer>(); deba@1845: writers.push_back(make_pair(name, new _writer_bits:: deba@1845: ValueWriter(value, writer))); deba@1409: return *this; deba@1409: } deba@1409: deba@1409: protected: deba@1409: deba@1409: /// \brief The header of section. deba@1409: /// deba@1409: /// It gives back the header of the section. deba@1409: std::string header() { deba@1901: return "@attributes " + name; deba@1409: } deba@1409: deba@1409: /// \brief Writer function of the section. deba@1409: /// deba@1409: /// Write the content of the section. deba@1409: void write(std::ostream& os) { deba@1409: typename Writers::iterator it; deba@1409: for (it = writers.begin(); it != writers.end(); ++it) { deba@1409: os << it->first << ' '; deba@1409: it->second->write(os); deba@1409: os << std::endl; deba@1409: } deba@1409: } deba@1409: deba@1409: private: deba@1901: std::string name; deba@1409: deba@1845: typedef std::vector > Writers; deba@1409: Writers writers; deba@1409: }; deba@1409: deba@1409: deba@1409: } deba@1409: #endif