diff -r 892c29484414 -r d2d1f8fa187b src/lemon/lemon_writer.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/lemon/lemon_writer.h Wed May 11 11:50:13 2005 +0000 @@ -0,0 +1,813 @@ +/* -*- C++ -*- + * src/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 + + +namespace lemon { + + /// \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); + } + + /// \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) {} + + // Writers + + 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; + + const Map& 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 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(is, value); + } + private: + const Value& value; + Writer writer; + }; + + + template + class IdWriterBase { + public: + typedef _Item Item; + virtual void write(std::ostream&, const Item&) 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 { + return idWriter.writeId(os, item); + } + }; + }; + + /// \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 Item; + + /// \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& writeMap(std::string name, const Map& map) { + return writeMap, 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& writeMap(std::string name, const Map& map, + const Writer& writer = 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 Item& item) const { + if (forceIdMap) { + os << graph.id(item); + } else { + idMap->write(os, item); + } + } + + private: + + typedef std::vector*> > MapWriters; + MapWriters writers; + + WriterBase* idMap; + bool forceIdMap; + + const Graph& graph; + std::string id; + + }; + + /// \ingroup io_group + /// \brief SectionWriter for writing a graph's edgeset. + /// + /// 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 a 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::Edge Item; + + /// \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 when 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), + nodeIdWriter(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 node map writer command for the writer. + /// + /// Add a new node map writer command for the writer. + template + EdgeSetWriter& writeMap(std::string name, const Map& map) { + return writeMap, 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 + EdgeSetWriter& writeMap(std::string name, const Map& map, + const Writer& writer = 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) { + 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 Item& item) const { + if (forceIdMap) { + os << graph.id(item); + } else { + idMap->write(os, item); + } + } + + private: + + typedef std::vector*> > MapWriters; + MapWriters writers; + + WriterBase* idMap; + bool forceIdMap; + + const Graph& 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 Item; + 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), + idWriter(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 Item& 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) { + 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 > ItemWriters; + ItemWriters writers; + std::auto_ptr > idWriter; + }; + + /// \ingroup io_group + /// \brief SectionWriter for writeing 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 Item; + 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), + idWriter(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 NodeWriter. + /// + /// Add an edge writer command for the NodeWriter. + void writeEdge(const std::string& name, const Item& 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 "@edges " + 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) { + os << writers[i].first << ' '; + idWriter->write(os, *(writers[i].second)); + os << std::endl; + } + } + + private: + + std::string id; + + typedef std::vector > ItemWriters; + ItemWriters writers; + + std::auto_ptr > idWriter; + }; + + /// \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()) { + 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