/* -*- C++ -*- * lemon/lemon_writer.h - Part of LEMON, a generic C++ optimization library * * Copyright (C) 2005 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 io_group ///\file ///\brief Lemon Format writer. #ifndef LEMON_LEMON_WRITER_H #define LEMON_LEMON_WRITER_H #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace lemon { namespace _writer_bits { template class ItemIdWriter { public: bool isIdWriter() { return true; } void writeId(std::ostream&, const Item&) {} template struct Constraints { void constraints() { bool b = writer.isIdWriter(); ignore_unused_variable_warning(b); writer.writeId(os, item); } _ItemIdWriter& writer; std::ostream& os; const Item& item; }; }; template class ItemWriter { public: void write(std::ostream&, const Item&) {} template struct Constraints { void constraints() { writer.write(os, item); } _ItemWriter& writer; std::ostream& os; const Item& item; }; }; } /// \ingroup io_group /// \brief Lemon Format writer class. /// /// The Lemon Format contains several sections. We do not want to /// determine what sections are in a lemon file we give only a framework /// to write a section oriented format. /// /// In the Lemon Format each section starts with a line contains a \c \@ /// character on the first not white space position. This line is the /// header line of the section. Each next lines belong to this section /// while it does not starts with \c \@ character. This line can start a /// new section or if it can close the file with the \c \@end line. /// The file format ignore the empty lines and it may contain comments /// started with a \c # character to the end of the line. /// /// The framework provides an abstract LemonWriter::SectionWriter class /// what defines the interface of a SectionWriter. The SectionWriter /// has the \c header() member function what gives back the header of the /// section. After that it will be called the \c write() member which /// should write the content of the section. /// /// \relates GraphWriter /// \relates NodeSetWriter /// \relates EdgeSetWriter /// \relates NodesWriter /// \relates EdgesWriter /// \relates AttributeWriter class LemonWriter { public: /// \brief Abstract base class for writing a section. /// /// This class has an \c header() member function what gives back /// the header line of the section. The \c write() member should /// write the content of the section to the stream. class SectionWriter { friend class LemonWriter; protected: /// \brief Constructor for SectionWriter. /// /// Constructor for SectionWriter. It attach this writer to /// the given LemonWriter. SectionWriter(LemonWriter& writer) { writer.attach(*this); } virtual ~SectionWriter() {} /// \brief The header of section. /// /// It gives back the header of the section. virtual std::string header() = 0; /// \brief Writer function of the section. /// /// Write the content of the section. virtual void write(std::ostream& os) = 0; }; /// \brief Constructor for LemonWriter. /// /// Constructor for LemonWriter which writes to the given stream. LemonWriter(std::ostream& _os) : os(&_os), own_os(false) {} /// \brief Constructor for LemonWriter. /// /// Constructor for LemonWriter which writes to the given file. LemonWriter(const std::string& filename) : os(0), own_os(true) { os = new std::ofstream(filename.c_str()); } /// \brief Desctructor for LemonWriter. /// /// Desctructor for LemonWriter. ~LemonWriter() { if (own_os) { delete os; } } private: LemonWriter(const LemonWriter&); void operator=(const LemonWriter&); void attach(SectionWriter& writer) { writers.push_back(&writer); } public: /// \brief Executes the LemonWriter. /// /// It executes the LemonWriter. void run() { SectionWriters::iterator it; for (it = writers.begin(); it != writers.end(); ++it) { *os << (*it)->header() << std::endl; (*it)->write(*os); } *os << "@end" << std::endl; } private: std::ostream* os; bool own_os; typedef std::vector SectionWriters; SectionWriters writers; }; /// \brief Helper class for implementing the common SectionWriters. /// /// Helper class for implementing the common SectionWriters. class CommonSectionWriterBase : public LemonWriter::SectionWriter { typedef LemonWriter::SectionWriter Parent; protected: /// \brief Constructor for CommonSectionWriterBase. /// /// Constructor for CommonSectionWriterBase. It attach this writer to /// the given LemonWriter. CommonSectionWriterBase(LemonWriter& _writer) : Parent(_writer) {} template class WriterBase { public: typedef _Item Item; virtual ~WriterBase() {} virtual void write(std::ostream& os, const Item& item) = 0; }; template class MapWriter : public WriterBase<_Item> { public: typedef _Map Map; typedef _Writer Writer; typedef typename Writer::Value Value; typedef _Item Item; typename SmartConstReference::Type map; Writer writer; MapWriter(const Map& _map, const Writer& _writer) : map(_map), writer(_writer) {} virtual ~MapWriter() {} virtual void write(std::ostream& os, const Item& item) { Value value = map[item]; writer.write(os, value); } }; class ValueWriterBase { public: virtual ~ValueWriterBase() {} virtual void write(std::ostream&) = 0; }; template class ValueWriter : public ValueWriterBase { public: typedef _Value Value; typedef _Writer Writer; ValueWriter(const Value& _value, const Writer& _writer) : value(_value), writer(_writer) {} virtual void write(std::ostream& os) { writer.write(os, value); } private: const Value& value; Writer writer; }; template class IdWriterBase { public: typedef _Item Item; virtual ~IdWriterBase() {} virtual void write(std::ostream&, const Item&) const = 0; virtual bool isIdWriter() const = 0; }; template class IdWriter : public IdWriterBase<_Item> { public: typedef _Item Item; typedef _BoxedIdWriter BoxedIdWriter; const BoxedIdWriter& idWriter; IdWriter(const BoxedIdWriter& _idWriter) : idWriter(_idWriter) {} virtual void write(std::ostream& os, const Item& item) const { idWriter.writeId(os, item); } virtual bool isIdWriter() const { return idWriter.isIdWriter(); } }; }; /// \ingroup io_group /// \brief SectionWriter for writing a graph's nodeset. /// /// The lemon format can store multiple graph nodesets with several maps. /// The nodeset section's header line is \c \@nodeset \c nodeset_id, but the /// \c nodeset_id may be empty. /// /// The first line of the section contains the names of the maps separated /// with white spaces. Each next lines describes a node in the nodeset, and /// contains the mapped values for each map. /// /// If the nodeset contains an \c "id" named map then it will be regarded /// as id map. This map should contain only unique values and when the /// \c writeId() member will be called with a node it will write it's id. /// Otherwise if the \c _forceIdMap constructor parameter is true then /// the id map will be the id in the graph. /// /// \relates LemonWriter template class NodeSetWriter : public CommonSectionWriterBase { typedef CommonSectionWriterBase Parent; public: typedef _Graph Graph; typedef _Traits Traits; typedef typename Graph::Node Node; /// \brief Constructor. /// /// Constructor for NodeSetWriter. It creates the NodeSetWriter and /// attach it into the given LemonWriter. If the \c _forceIdMap /// parameter is true then the writer will write own id map when /// the user does not give "id" named map. NodeSetWriter(LemonWriter& _writer, const Graph& _graph, const std::string& _id = std::string(), bool _forceIdMap = true) : Parent(_writer), idMap(0), forceIdMap(_forceIdMap), graph(_graph), id(_id) {} /// \brief Destructor. /// /// Destructor for NodeSetWriter. virtual ~NodeSetWriter() { typename MapWriters::iterator it; for (it = writers.begin(); it != writers.end(); ++it) { delete it->second; } } private: NodeSetWriter(const NodeSetWriter&); void operator=(const NodeSetWriter&); public: /// \brief Add a new node map writer command for the writer. /// /// Add a new node map writer command for the writer. template NodeSetWriter& writeNodeMap(std::string name, const Map& map) { return writeNodeMap, Map>(name, map); } /// \brief Add a new node map writer command for the writer. /// /// Add a new node map writer command for the writer. template NodeSetWriter& writeNodeMap(std::string name, const Map& map, const Writer& writer = Writer()) { checkConcept, Map>(); checkConcept<_writer_bits::ItemWriter, Writer>(); writers.push_back( make_pair(name, new MapWriter(map, writer))); return *this; } protected: /// \brief The header of the section. /// /// It gives back the header of the section. virtual std::string header() { return "@nodeset " + id; } /// \brief Writer function of the section. /// /// Write the content of the section. virtual void write(std::ostream& os) { for (int i = 0; i < (int)writers.size(); ++i) { if (writers[i].first == "id") { idMap = writers[i].second; forceIdMap = false; break; } } if (forceIdMap) { os << "id\t"; } for (int i = 0; i < (int)writers.size(); ++i) { os << writers[i].first << '\t'; } os << std::endl; for (typename Graph::NodeIt it(graph); it != INVALID; ++it) { if (forceIdMap) { os << graph.id(it) << '\t'; } for (int i = 0; i < (int)writers.size(); ++i) { writers[i].second->write(os, it); os << '\t'; } os << std::endl; } } public: /// \brief Returns true if the nodeset can write the ids of the nodes. /// /// Returns true if the nodeset can write the ids of the nodes. /// It is possible only if an "id" named map was written or the /// \c _forceIdMap constructor parameter was true. bool isIdWriter() const { return idMap != 0 || forceIdMap; } /// \brief Write the id of the given node. /// /// It writes the id of the given node. If there was written an "id" /// named map then it will write the map value belongs to the node. /// Otherwise if the \c forceId parameter was true it will write /// its id in the graph. void writeId(std::ostream& os, const Node& item) const { if (forceIdMap) { os << graph.id(item); } else { idMap->write(os, item); } } private: typedef std::vector*> > MapWriters; MapWriters writers; WriterBase* idMap; bool forceIdMap; typename SmartConstReference::Type graph; std::string id; }; /// \ingroup io_group /// \brief SectionWriter for writing a graph's edgesets. /// /// The lemon format can store multiple graph edgesets with several maps. /// The edgeset section's header line is \c \@edgeset \c edgeset_id, but the /// \c edgeset_id may be empty. /// /// The first line of the section contains the names of the maps separated /// with white spaces. Each next lines describes a edge in the edgeset. The /// line contains the source and the target nodes' id and the mapped /// values for each map. /// /// If the edgeset contains an \c "id" named map then it will be regarded /// as id map. This map should contain only unique values and when the /// \c writeId() member will be called with an edge it will write it's id. /// Otherwise if the \c _forceIdMap constructor parameter is true then /// the id map will be the id in the graph. /// /// The edgeset writer needs a node id writer to identify which nodes /// have to be connected. If a NodeSetWriter can write the nodes' id, /// it will be able to use with this class. /// /// \relates LemonWriter template class EdgeSetWriter : public CommonSectionWriterBase { typedef CommonSectionWriterBase Parent; public: typedef _Graph Graph; typedef _Traits Traits; typedef typename Graph::Node Node; typedef typename Graph::Edge Edge; /// \brief Constructor. /// /// Constructor for EdgeSetWriter. It creates the EdgeSetWriter and /// attach it into the given LemonWriter. It will write node ids by /// the \c _nodeIdWriter. If the \c _forceIdMap parameter is true /// then the writer will write own id map if the user does not give /// "id" named map. template EdgeSetWriter(LemonWriter& _writer, const Graph& _graph, const NodeIdWriter& _nodeIdWriter, const std::string& _id = std::string(), bool _forceIdMap = true) : Parent(_writer), idMap(0), forceIdMap(_forceIdMap), graph(_graph), id(_id) { checkConcept<_writer_bits::ItemIdWriter, NodeIdWriter>(); nodeIdWriter.reset(new IdWriter(_nodeIdWriter)); } /// \brief Destructor. /// /// Destructor for EdgeSetWriter. virtual ~EdgeSetWriter() { typename MapWriters::iterator it; for (it = writers.begin(); it != writers.end(); ++it) { delete it->second; } } private: EdgeSetWriter(const EdgeSetWriter&); void operator=(const EdgeSetWriter&); public: /// \brief Add a new edge map writer command for the writer. /// /// Add a new edge map writer command for the writer. template EdgeSetWriter& writeEdgeMap(std::string name, const Map& map) { return writeEdgeMap, Map>(name, map); } /// \brief Add a new edge map writer command for the writer. /// /// Add a new edge map writer command for the writer. template EdgeSetWriter& writeEdgeMap(std::string name, const Map& map, const Writer& writer = Writer()) { checkConcept, Map>(); checkConcept<_writer_bits::ItemWriter, Writer>(); writers.push_back( make_pair(name, new MapWriter(map, writer))); return *this; } protected: /// \brief The header of the section. /// /// It gives back the header of the section. virtual std::string header() { return "@edgeset " + id; } /// \brief Writer function of the section. /// /// Write the content of the section. virtual void write(std::ostream& os) { if (!nodeIdWriter->isIdWriter()) { throw DataFormatError("Cannot find nodeset or ID map"); } for (int i = 0; i < (int)writers.size(); ++i) { if (writers[i].first == "id") { idMap = writers[i].second; forceIdMap = false; break; } } os << "\t\t"; if (forceIdMap) { os << "id\t"; } for (int i = 0; i < (int)writers.size(); ++i) { os << writers[i].first << '\t'; } os << std::endl; for (typename Graph::EdgeIt it(graph); it != INVALID; ++it) { nodeIdWriter->write(os, graph.source(it)); os << '\t'; nodeIdWriter->write(os, graph.target(it)); os << '\t'; if (forceIdMap) { os << graph.id(it) << '\t'; } for (int i = 0; i < (int)writers.size(); ++i) { writers[i].second->write(os, it); os << '\t'; } os << std::endl; } } public: /// \brief Returns true if the edgeset can write the ids of the edges. /// /// Returns true if the edgeset can write the ids of the edges. /// It is possible only if an "id" named map was written or the /// \c _forceIdMap constructor parameter was true. bool isIdWriter() const { return forceIdMap || idMap != 0; } /// \brief Write the id of the given edge. /// /// It writes the id of the given edge. If there was written an "id" /// named map then it will write the map value belongs to the edge. /// Otherwise if the \c forceId parameter was true it will write /// its id in the graph. void writeId(std::ostream& os, const Edge& item) const { if (forceIdMap) { os << graph.id(item); } else { idMap->write(os, item); } } private: typedef std::vector*> > MapWriters; MapWriters writers; WriterBase* idMap; bool forceIdMap; typename SmartConstReference::Type graph; std::string id; std::auto_ptr > nodeIdWriter; }; /// \ingroup io_group /// \brief SectionWriter for writing a undirected edgeset. /// /// The lemon format can store multiple undirected edgesets with several /// maps. The undirected edgeset section's header line is \c \@undiredgeset /// \c undiredgeset_id, but the \c undiredgeset_id may be empty. /// /// The first line of the section contains the names of the maps separated /// with white spaces. Each next lines describes an undirected edge in the /// edgeset. The line contains the two connected nodes' id and the mapped /// values for each undirected map. /// /// The section can handle the directed as a syntactical sugar. Two /// undirected edge map describes one directed edge map. This two maps /// are the forward map and the backward map and the names of this map /// is near the same just with a prefix \c '+' or \c '-' character /// difference. /// /// If the edgeset contains an \c "id" named map then it will be regarded /// as id map. This map should contain only unique values and when the /// \c writeId() member will be called with an undirected edge it will /// write it's id. Otherwise if the \c _forceIdMap constructor parameter /// is true then the id map will be the id in the graph. /// /// The undirected edgeset writer needs a node id writer to identify /// which nodes have to be connected. If a NodeSetWriter can write the /// nodes' id, it will be able to use with this class. /// /// \relates LemonWriter template class UndirEdgeSetWriter : public CommonSectionWriterBase { typedef CommonSectionWriterBase Parent; public: typedef _Graph Graph; typedef _Traits Traits; typedef typename Graph::Node Node; typedef typename Graph::Edge Edge; typedef typename Graph::UndirEdge UndirEdge; /// \brief Constructor. /// /// Constructor for UndirEdgeSetWriter. It creates the UndirEdgeSetWriter /// and attach it into the given LemonWriter. It will write node ids by /// the \c _nodeIdWriter. If the \c _forceIdMap parameter is true /// then the writer will write own id map if the user does not give /// "id" named map. template UndirEdgeSetWriter(LemonWriter& _writer, const Graph& _graph, const NodeIdWriter& _nodeIdWriter, const std::string& _id = std::string(), bool _forceIdMap = true) : Parent(_writer), idMap(0), forceIdMap(_forceIdMap), graph(_graph), id(_id) { checkConcept<_writer_bits::ItemIdWriter, NodeIdWriter>(); nodeIdWriter.reset(new IdWriter(_nodeIdWriter)); } /// \brief Destructor. /// /// Destructor for UndirEdgeSetWriter. virtual ~UndirEdgeSetWriter() { typename MapWriters::iterator it; for (it = writers.begin(); it != writers.end(); ++it) { delete it->second; } } private: UndirEdgeSetWriter(const UndirEdgeSetWriter&); void operator=(const UndirEdgeSetWriter&); public: /// \brief Add a new undirected edge map writer command for the writer. /// /// Add a new undirected map writer command for the writer. template UndirEdgeSetWriter& writeUndirEdgeMap(std::string name, const Map& map) { return writeUndirEdgeMap, Map>(name, map); } /// \brief Add a new undirected map writer command for the writer. /// /// Add a new undirected map writer command for the writer. template UndirEdgeSetWriter& writeUndirEdgeMap(std::string name, const Map& map, const Writer& writer = Writer()) { checkConcept, Map>(); checkConcept<_writer_bits::ItemWriter, Writer>(); writers.push_back( make_pair(name, new MapWriter(map, writer))); return *this; } /// \brief Add a new directed edge map writer command for the writer. /// /// Add a new directed map writer command for the writer. template UndirEdgeSetWriter& writeEdgeMap(std::string name, const Map& map) { return writeEdgeMap, Map>(name, map); } /// \brief Add a new directed map writer command for the writer. /// /// Add a new directed map writer command for the writer. template UndirEdgeSetWriter& writeEdgeMap(std::string name, const Map& map, const Writer& writer = Writer()) { checkConcept, Map>(); checkConcept<_writer_bits::ItemWriter, Writer>(); writeUndirEdge("+" + name, composeMap(forwardMap(graph), map), writer); writeUndirEdge("-" + name, composeMap(backwardMap(graph), map), writer); return *this; } protected: /// \brief The header of the section. /// /// It gives back the header of the section. virtual std::string header() { return "@undiredgeset " + id; } /// \brief Writer function of the section. /// /// Write the content of the section. virtual void write(std::ostream& os) { if (!nodeIdWriter->isIdWriter()) { throw DataFormatError("Cannot find nodeset or ID map"); } for (int i = 0; i < (int)writers.size(); ++i) { if (writers[i].first == "id") { idMap = writers[i].second; forceIdMap = false; break; } } os << "\t\t"; if (forceIdMap) { os << "id\t"; } for (int i = 0; i < (int)writers.size(); ++i) { os << writers[i].first << '\t'; } os << std::endl; for (typename Graph::UndirEdgeIt it(graph); it != INVALID; ++it) { nodeIdWriter->write(os, graph.source(it)); os << '\t'; nodeIdWriter->write(os, graph.target(it)); os << '\t'; if (forceIdMap) { os << graph.id(it) << '\t'; } for (int i = 0; i < (int)writers.size(); ++i) { writers[i].second->write(os, it); os << '\t'; } os << std::endl; } } public: /// \brief Returns true if the undirected edgeset can write the ids of /// the edges. /// /// Returns true if the undirected edgeset can write the ids of the /// undirected edges. It is possible only if an "id" named map was /// written or the \c _forceIdMap constructor parameter was true. bool isIdWriter() const { return forceIdMap || idMap != 0; } /// \brief Write the id of the given undirected edge. /// /// It writes the id of the given undirected edge. If there was written /// an "id" named map then it will write the map value belongs to the /// undirected edge. Otherwise if the \c forceId parameter was true it /// will write its id in the graph. void writeId(std::ostream& os, const UndirEdge& item) const { if (forceIdMap) { os << graph.id(item); } else { idMap->write(os, item); } } /// \brief Write the id of the given edge. /// /// It writes the id of the given edge. If there was written /// an "id" named map then it will write the map value belongs to the /// edge. Otherwise if the \c forceId parameter was true it /// will write its id in the graph. If the edge is forward map /// then its prefix character is \c '+' elsewhere \c '-'. void writeId(std::ostream& os, const Edge& item) const { if (graph.forward(item)) { os << "+ "; } else { os << "- "; } if (forceIdMap) { os << graph.id(item); } else { idMap->write(os, item); } } private: typedef std::vector*> > MapWriters; MapWriters writers; WriterBase* idMap; bool forceIdMap; typename SmartConstReference::Type graph; std::string id; std::auto_ptr > nodeIdWriter; }; /// \ingroup io_group /// \brief SectionWriter for writing labeled nodes. /// /// The nodes section's header line is \c \@nodes \c nodes_id, but the /// \c nodes_id may be empty. /// /// Each line in the section contains the label of the node and /// then the node id. /// /// \relates LemonWriter template class NodeWriter : public CommonSectionWriterBase { typedef CommonSectionWriterBase Parent; typedef _Graph Graph; typedef typename Graph::Node Node; public: /// \brief Constructor. /// /// Constructor for NodeWriter. It creates the NodeWriter and /// attach it into the given LemonWriter. The given \c _IdWriter /// will write the nodes' id what can be a nodeset writer. template NodeWriter(LemonWriter& _writer, const _IdWriter& _idWriter, const std::string& _id = std::string()) : Parent(_writer), id(_id) { checkConcept<_writer_bits::ItemIdWriter, _IdWriter>(); idWriter.reset(new IdWriter(_idWriter)); } /// \brief Destructor. /// /// Destructor for NodeWriter. virtual ~NodeWriter() {} private: NodeWriter(const NodeWriter&); void operator=(const NodeWriter&); public: /// \brief Add a node writer command for the NodeWriter. /// /// Add a node writer command for the NodeWriter. void writeNode(const std::string& name, const Node& item) { writers.push_back(make_pair(name, &item)); } protected: /// \brief Header checking function. /// /// It gives back true when the header line start with \c \@nodes, /// and the header line's id and the writer's id are the same. virtual std::string header() { return "@nodes " + id; } /// \brief Writer function of the section. /// /// Write the content of the section. virtual void write(std::ostream& os) { if (!idWriter->isIdWriter()) { throw DataFormatError("Cannot find nodeset or ID map"); } for (int i = 0; i < (int)writers.size(); ++i) { os << writers[i].first << ' '; idWriter->write(os, *(writers[i].second)); os << std::endl; } } private: std::string id; typedef std::vector > NodeWriters; NodeWriters writers; std::auto_ptr > idWriter; }; /// \ingroup io_group /// \brief SectionWriter for writing labeled edges. /// /// The edges section's header line is \c \@edges \c edges_id, but the /// \c edges_id may be empty. /// /// Each line in the section contains the label of the edge and /// then the edge id. /// /// \relates LemonWriter template class EdgeWriter : public CommonSectionWriterBase { typedef CommonSectionWriterBase Parent; typedef _Graph Graph; typedef typename Graph::Edge Edge; public: /// \brief Constructor. /// /// Constructor for EdgeWriter. It creates the EdgeWriter and /// attach it into the given LemonWriter. The given \c _IdWriter /// will write the edges' id what can be a edgeset writer. template EdgeWriter(LemonWriter& _writer, const _IdWriter& _idWriter, const std::string& _id = std::string()) : Parent(_writer), id(_id) { checkConcept<_writer_bits::ItemIdWriter, _IdWriter>(); idWriter.reset(new IdWriter(_idWriter)); } /// \brief Destructor. /// /// Destructor for EdgeWriter. virtual ~EdgeWriter() {} private: EdgeWriter(const EdgeWriter&); void operator=(const EdgeWriter&); public: /// \brief Add an edge writer command for the EdgeWriter. /// /// Add an edge writer command for the EdgeWriter. void writeEdge(const std::string& name, const Edge& item) { writers.push_back(make_pair(name, &item)); } protected: /// \brief Header checking function. /// /// It gives back true when the header line start with \c \@edges, /// and the header line's id and the writer's id are the same. virtual std::string header() { return "@edges " + id; } /// \brief Writer function of the section. /// /// Write the content of the section. virtual void write(std::ostream& os) { if (!idWriter->isIdWriter()) { throw DataFormatError("Cannot find edgeset or ID map"); } for (int i = 0; i < (int)writers.size(); ++i) { os << writers[i].first << ' '; idWriter->write(os, *(writers[i].second)); os << std::endl; } } private: std::string id; typedef std::vector > EdgeWriters; EdgeWriters writers; std::auto_ptr > idWriter; }; /// \ingroup io_group /// \brief SectionWriter for writing labeled undirected edges. /// /// The undirected edges section's header line is \c \@undiredges /// \c undiredges_id, but the \c undiredges_id may be empty. /// /// Each line in the section contains the label of the undirected edge and /// then the undirected edge id. /// /// \relates LemonWriter template class UndirEdgeWriter : public CommonSectionWriterBase { typedef CommonSectionWriterBase Parent; typedef _Graph Graph; typedef typename Graph::Node Node; typedef typename Graph::Edge Edge; typedef typename Graph::UndirEdge UndirEdge; public: /// \brief Constructor. /// /// Constructor for UndirEdgeWriter. It creates the UndirEdgeWriter and /// attach it into the given LemonWriter. The given \c _IdWriter /// will write the undirected edges' id what can be an undirected /// edgeset writer. template UndirEdgeWriter(LemonWriter& _writer, const _IdWriter& _idWriter, const std::string& _id = std::string()) : Parent(_writer), id(_id) { checkConcept<_writer_bits::ItemIdWriter, _IdWriter>(); checkConcept<_writer_bits::ItemIdWriter, _IdWriter>(); undirEdgeIdWriter.reset(new IdWriter(_idWriter)); edgeIdWriter.reset(new IdWriter(_idWriter)); } /// \brief Destructor. /// /// Destructor for UndirEdgeWriter. virtual ~UndirEdgeWriter() {} private: UndirEdgeWriter(const UndirEdgeWriter&); void operator=(const UndirEdgeWriter&); public: /// \brief Add an edge writer command for the UndirEdgeWriter. /// /// Add an edge writer command for the UndirEdgeWriter. void writeEdge(const std::string& name, const Edge& item) { edgeWriters.push_back(make_pair(name, &item)); } /// \brief Add an undirected edge writer command for the UndirEdgeWriter. /// /// Add an undirected edge writer command for the UndirEdgeWriter. void writeUndirEdge(const std::string& name, const UndirEdge& item) { undirEdgeWriters.push_back(make_pair(name, &item)); } protected: /// \brief Header checking function. /// /// It gives back true when the header line start with \c \@undiredges, /// and the header line's id and the writer's id are the same. virtual std::string header() { return "@undiredges " + id; } /// \brief Writer function of the section. /// /// Write the content of the section. virtual void write(std::ostream& os) { if (!edgeIdWriter->isIdWriter()) { throw DataFormatError("Cannot find undirected edgeset or ID map"); } if (!undirEdgeIdWriter->isIdWriter()) { throw DataFormatError("Cannot find undirected edgeset or ID map"); } for (int i = 0; i < (int)undirEdgeWriters.size(); ++i) { os << undirEdgeWriters[i].first << ' '; undirEdgeIdWriter->write(os, *(undirEdgeWriters[i].second)); os << std::endl; } for (int i = 0; i < (int)edgeWriters.size(); ++i) { os << edgeWriters[i].first << ' '; edgeIdWriter->write(os, *(edgeWriters[i].second)); os << std::endl; } } private: std::string id; typedef std::vector > UndirEdgeWriters; UndirEdgeWriters undirEdgeWriters; std::auto_ptr > undirEdgeIdWriter; typedef std::vector > EdgeWriters; EdgeWriters edgeWriters; std::auto_ptr > edgeIdWriter; }; /// \ingroup io_group /// \brief SectionWriter for attributes. /// /// The lemon format can store multiple attribute set. Each set has /// the header line \c \@attributes \c attributeset_id, but the /// attributeset_id may be empty. /// /// The attributeset section contains several lines. Each of them starts /// with the name of attribute and then the value. /// /// \relates LemonWriter template class AttributeWriter : public CommonSectionWriterBase { typedef CommonSectionWriterBase Parent; typedef _Traits Traits; public: /// \brief Constructor. /// /// Constructor for AttributeWriter. It creates the AttributeWriter and /// attach it into the given LemonWriter. AttributeWriter(LemonWriter& _writer, const std::string& _id = std::string()) : Parent(_writer), id(_id) {} /// \brief Destructor. /// /// Destructor for AttributeWriter. virtual ~AttributeWriter() { typename Writers::iterator it; for (it = writers.begin(); it != writers.end(); ++it) { delete it->second; } } private: AttributeWriter(const AttributeWriter&); void operator=(AttributeWriter&); public: /// \brief Add an attribute writer command for the writer. /// /// Add an attribute writer command for the writer. template AttributeWriter& writeAttribute(const std::string& id, const Value& value) { return writeAttribute >(id, value); } /// \brief Add an attribute writer command for the writer. /// /// Add an attribute writer command for the writer. template AttributeWriter& writeAttribute(const std::string& name, const Value& value, const Writer& writer = Writer()) { checkConcept<_writer_bits::ItemWriter, Writer>(); writers.push_back(make_pair(name, new ValueWriter (value, writer))); return *this; } protected: /// \brief The header of section. /// /// It gives back the header of the section. std::string header() { return "@attributes " + id; } /// \brief Writer function of the section. /// /// Write the content of the section. void write(std::ostream& os) { typename Writers::iterator it; for (it = writers.begin(); it != writers.end(); ++it) { os << it->first << ' '; it->second->write(os); os << std::endl; } } private: std::string id; typedef std::vector > Writers; Writers writers; }; } #endif