# HG changeset patch # User deba # Date 1115812213 0 # Node ID d2d1f8fa187bd326618da3d9b5825a233966a9d8 # Parent 892c294844148b9a5078de7ffc7cdafcc30606d4 LemonWriter and GraphWriter. Little bit better documentation. diff -r 892c29484414 -r d2d1f8fa187b src/lemon/Makefile.am --- a/src/lemon/Makefile.am Mon May 09 11:24:26 2005 +0000 +++ b/src/lemon/Makefile.am Wed May 11 11:50:13 2005 +0000 @@ -53,6 +53,7 @@ concept_check.h \ utility.h \ lemon_reader.h \ + lemon_writer.h \ graph_reader.h \ graph_writer.h \ bits/alteration_notifier.h \ @@ -66,7 +67,8 @@ bits/clearable_graph_extender.h \ bits/erasable_graph_extender.h \ bits/undir_graph_extender.h \ - bits/item_reader.h + bits/item_reader.h \ + bits/item_writer.h noinst_HEADERS = \ concept/graph.h \ diff -r 892c29484414 -r d2d1f8fa187b src/lemon/bits/item_writer.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/lemon/bits/item_writer.h Wed May 11 11:50:13 2005 +0000 @@ -0,0 +1,214 @@ +/* -*- C++ -*- + * src/lemon/bits/item_reader.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 Item writer bits for lemon output. + +#ifndef LEMON_BITS_ITEM_WRITER_H +#define LEMON_BITS_ITEM_WRITER_H + +#include +#include + +#include +#include +#include +#include + +namespace lemon { + + template + class DefaultWriter; + + /// \ingroup io_group + /// \brief Writer class for quoted strings. + /// + /// Writer class for quoted strings. It can process the escape + /// sequences in the string. + /// \author Balazs Dezso + class QuotedStringWriter { + public: + typedef std::string Value; + + /// \brief Constructor for the writer. + /// + /// Constructor for the writer. If the given parameter is true + /// the writer creates escape sequences from special characters. + QuotedStringWriter(bool _escaped = true) : escaped(_escaped) {} + + /// \brief Writes a quoted string to the given stream. + /// + /// Writes a quoted string to the given stream. + void write(std::ostream& os, const std::string& value) { + os << "\""; + if (escaped) { + std::ostringstream ls; + for (int i = 0; i < (int)value.size(); ++i) { + writeEscape(ls, value[i]); + } + os << ls.str(); + } else { + os << value; + } + os << "\""; + } + + private: + + static void writeEscape(std::ostream& os, char c) { + switch (c) { + case '\\': + os << "\\\\"; + return; + case '\"': + os << "\\\""; + return; + case '\'': + os << "\\\'"; + return; + case '\?': + os << "\\\?"; + return; + case '\a': + os << "\\a"; + return; + case '\b': + os << "\\b"; + return; + case '\f': + os << "\\f"; + return; + case '\r': + os << "\\r"; + return; + case '\n': + os << "\\n"; + return; + case '\t': + os << "\\t"; + return; + case '\v': + os << "\\v"; + return; + default: + if (c < 0x20) { + os << '\\' << std::oct << (int)c; + } else { + os << c; + } + return; + } + } + private: + bool escaped; + }; + + /// \ingroup io_group + /// + /// \brief Writer for standard containers. + /// + /// Writer for each iterable standard containers. The representation + /// of the container is the values enumerated between an open and a + /// close parse. + /// + /// \author Balazs Dezso + template < + typename _Container, + typename _ItemWriter = DefaultWriter + > + class IterableWriter { + public: + typedef _Container Value; + typedef _ItemWriter ItemWriter; + + private: + + ItemWriter item_writer; + + public: + + /// \brief Writes the values of the container to the given stream. + /// + /// Writes the values of the container to the given stream. + void write(std::ostream& os, const Value& value) const { + typename Value::const_iterator it; + os << '('; + for (it = value.begin(); it != value.end(); ++it) { + item_writer.write(os, *it); + os << ' '; + } + os << ')'; + } + + }; + + /// \ingroup io_group + /// + /// \brief The default item writer template class. + /// + /// The default item writer template class. If some section writer + /// needs to write a value to the stream it will give the default way for it. + /// + /// \author Balazs Dezso + template + class DefaultWriter { + public: + /// The value type. + typedef _Value Value; + /// \brief Writes the value to the given stream. + /// + /// Writes the value to the given stream. + void write(std::ostream& os, const Value& value) const { + os << value; + } + }; + + template + class DefaultWriter > + : public IterableWriter > {}; + + template + class DefaultWriter > + : public IterableWriter > {}; + + template + class DefaultWriter > + : public IterableWriter > {}; + + template + class DefaultWriter > + : public IterableWriter > {}; + + template + class DefaultWriter > + : public IterableWriter > {}; + + /// \brief Standard WriterTraits for the section writers. + /// + /// Standard WriterTraits for the section writers. + /// It defines standard writing method for all type of value. + /// \author Balazs Dezso + struct DefaultWriterTraits { + + template + struct Writer : DefaultWriter<_Value> {}; + + }; + +} + +#endif diff -r 892c29484414 -r d2d1f8fa187b src/lemon/graph_writer.h --- a/src/lemon/graph_writer.h Mon May 09 11:24:26 2005 +0000 +++ b/src/lemon/graph_writer.h Wed May 11 11:50:13 2005 +0000 @@ -22,146 +22,15 @@ #define LEMON_GRAPH_WRITER_H #include -#include -#include -#include - -#include - -#include - -#include #include - +#include namespace lemon { /// \addtogroup io_group /// @{ - /// \brief Standard WriterTraits for the GraphWriter class. - /// - /// Standard WriterTraits for the GraphWriter class. - /// It defines standard writing method for all type of value. - /// \author Balazs Dezso - struct DefaultWriterTraits { - - /// \brief Template class for writing an value. - /// - /// Template class for writing an value. - /// \author Balazs Dezso - template - struct Writer { - /// The value type. - typedef _Value Value; - - /// \brief Writes a value to the given stream. - /// - /// Writes a value to the given stream. - void write(std::ostream& os, const Value& value) { - os << value << '\t'; - } - }; - - /// \brief Returns wheter this name is an ID map name. - /// - /// Returns wheter this name is an ID map name. - static bool idMapName(const std::string& name) { - return name == "id"; - } - - }; - - - /// \brief Writer class for quoted strings. - /// - /// Writer class for quoted strings. It can process the escape - /// sequences in the string. - /// \author Balazs Dezso - class QuotedStringWriter { - public: - typedef std::string Value; - - /// \brief Constructor for the writer. - /// - /// Constructor for the writer. If the given parameter is true - /// the writer creates escape sequences from special characters. - QuotedStringWriter(bool _escaped = true) : escaped(_escaped) {} - - /// \brief Writes a quoted string to the given stream. - /// - /// Writes a quoted string to the given stream. - void write(std::ostream& os, const std::string& value) { - os << "\""; - if (escaped) { - std::ostringstream ls; - for (int i = 0; i < (int)value.size(); ++i) { - writeEscape(ls, value[i]); - } - os << ls.str(); - } else { - os << value; - } - os << "\""; - } - - private: - - static void writeEscape(std::ostream& os, char c) { - switch (c) { - case '\\': - os << "\\\\"; - return; - case '\"': - os << "\\\""; - return; - case '\'': - os << "\\\'"; - return; - case '\?': - os << "\\\?"; - return; - case '\a': - os << "\\a"; - return; - case '\b': - os << "\\b"; - return; - case '\f': - os << "\\f"; - return; - case '\r': - os << "\\r"; - return; - case '\n': - os << "\\n"; - return; - case '\t': - os << "\\t"; - return; - case '\v': - os << "\\v"; - return; - default: - if (c < 0x20) { - os << '\\' << std::oct << (int)c; - } else { - os << c; - } - return; - } - } - private: - bool escaped; - }; - - class GUIWriter { - public: - virtual void write(std::ostream& os) = 0; - }; - - /// \brief The graph writer class. /// /// The \c GraphWriter class provides the graph output. To write a graph @@ -231,46 +100,64 @@ typedef _Graph Graph; typedef typename Graph::Node Node; - typedef typename Graph::NodeIt NodeIt; typedef typename Graph::Edge Edge; - typedef typename Graph::EdgeIt EdgeIt; typedef _WriterTraits WriterTraits; - + /// \brief Construct a new GraphWriter. /// - /// Construct a new GraphWriter. It writes from the given map, - /// it constructs the given map and it use the given writer as the - /// default skipper. + /// Construct a new GraphWriter. It writes the given graph + /// to the given stream. GraphWriter(std::ostream& _os, const Graph& _graph) - : gui_writer(0), os(_os), graph(_graph){} + : writer(new LemonWriter(_os)), own_writer(true), + graph(_graph), + nodeset_writer(*writer, graph, std::string()), + edgeset_writer(*writer, graph, nodeset_writer, std::string()), + node_writer(*writer, nodeset_writer, std::string()), + edge_writer(*writer, edgeset_writer, std::string()), + attribute_writer(*writer, std::string()) {} + /// \brief Construct a new GraphWriter. + /// + /// Construct a new GraphWriter. It writes into the given graph + /// to the given file. + GraphWriter(const std::string& _filename, const Graph& _graph) + : writer(new LemonWriter(_filename)), own_writer(true), + graph(_graph), + nodeset_writer(*writer, graph, std::string(), skipper), + edgeset_writer(*writer, graph, nodeset_writer, std::string(), skipper), + node_writer(*writer, nodeset_writer, std::string()), + edge_writer(*writer, edgeset_writer, std::string()), + attribute_writer(*writer, std::string()) {} + + /// \brief Construct a new GraphWriter. + /// + /// Construct a new GraphWriter. It writes into the given graph + /// to given LemonReader. + GraphWriter(LemonWriter& _writer, const Graph& _graph) + : writer(_writer), own_writer(false), + graph(_graph), + nodeset_writer(*writer, graph, std::string()), + edgeset_writer(*writer, graph, nodeset_writer, std::string()), + node_writer(*writer, nodeset_writer, std::string()), + edge_writer(*writer, edgeset_writer, std::string()), + attribute_writer(*writer, std::string()) {} /// \brief Destruct the graph writer. /// /// Destruct the graph writer. ~GraphWriter() { - for (typename NodeMapWriters::iterator it = node_map_writers.begin(); - it != node_map_writers.end(); ++it) { - delete it->second; - } - - for (typename EdgeMapWriters::iterator it = edge_map_writers.begin(); - it != edge_map_writers.end(); ++it) { - delete it->second; - } - + if (own_writer) + delete writer; } - // Node map rules - /// \brief Add a new node map writer command for the writer. /// /// Add a new node map writer command for the writer. template GraphWriter& writeNodeMap(std::string name, const Map& map) { - return writeNodeMap, Map>(name, map); + nodeset_writer.writeMap(name, map); + return *this; } /// \brief Add a new node map writer command for the writer. @@ -278,21 +165,19 @@ /// Add a new node map writer command for the writer. template GraphWriter& writeNodeMap(std::string name, const Map& map, - const Writer& writer = Writer()) { - node_map_writers.push_back( - make_pair(name, new MapWriter(map, writer))); + const Writer& writer = Writer()) { + nodeset_writer.writeMap(name, map, writer); return *this; } - // Edge map rules /// \brief Add a new edge map writer command for the writer. /// /// Add a new edge map writer command for the writer. template GraphWriter& writeEdgeMap(std::string name, const Map& map) { - return writeEdgeMap, Map>(name, map); + edgeset_writer.writeMap(name, map); + return *this; } @@ -300,10 +185,9 @@ /// /// Add a new edge map writer command for the writer. template - GraphWriter& writeEdgeMap(std::string name, - const Map& map, const Writer& writer = Writer()) { - edge_map_writers.push_back(make_pair(name, - new MapWriter(map, writer))); + GraphWriter& writeEdgeMap(std::string name, const Map& map, + const Writer& writer = Writer()) { + edgeset_writer.writeMap(name, map, writer); return *this; } @@ -311,7 +195,7 @@ /// /// Add a new labeled node writer for the writer. GraphWriter& writeNode(std::string name, const Node& node) { - node_writers.push_back(make_pair(name, node)); + node_writer.writeNode(name, node); return *this; } @@ -319,160 +203,62 @@ /// /// Add a new labeled edge writer for the writer. GraphWriter& writeEdge(std::string name, const Edge& edge) { - edge_writers.push_back(make_pair(name, edge)); + edge_writer.writeEdge(name, edge); + } + + /// \brief Add a new attribute writer command. + /// + /// Add a new attribute writer command. + template + GraphWriter& writeAttribute(std::string name, const Value& value) { + attribute_writer.writeAttribute(name, value); + return *this; + } + + /// \brief Add a new attribute writer command. + /// + /// Add a new attribute writer command. + template + GraphWriter& writeAttribute(std::string name, const Value& value, + const Writer& writer) { + attribute_writer.writeAttribute(name, value, writer); return *this; } - GraphWriter& writeGUI(const GUIWriter& writer) { - gui_writer = &writer; + /// \brief Conversion operator to LemonWriter. + /// + /// Conversion operator to LemonWriter. It make possible + /// to access the encapsulated \e LemonWriter, this way + /// you can attach to this writer new instances of + /// \e LemonWriter::SectionWriter. + operator LemonWriter&() { + return *writer; } /// \brief Executes the writer commands. /// /// Executes the writer commands. - void run() { - WriterBase* nodeWriter = 0; - WriterBase* edgeWriter = 0; - writeNodeSet(nodeWriter); - writeEdgeSet(nodeWriter, edgeWriter); - writeNodes(nodeWriter); - writeEdges(edgeWriter); - writeGUI(); - os << "@end" << std::endl; + void run() { + writer->run(); } private: - template - class WriterBase { - public: - typedef _Item Item; - virtual void write(std::ostream&, const Item&) = 0; - }; + LemonWriter* writer; + bool own_writer; - 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 void write(std::ostream& os, const Item& item) { - writer.write(os, map[item]); - } - - }; - - void writeNodeSet(WriterBase* & nodeWriter) { - if (node_map_writers.size() == 0) return; - os << "@nodeset" << std::endl; - for (int i = 0; i < (int)node_map_writers.size(); ++i) { - const std::string& id = node_map_writers[i].first; - os << id << '\t'; - if (WriterTraits::idMapName(id) && nodeWriter == 0) { - nodeWriter = node_map_writers[i].second; - } - } - os << std::endl; - for (NodeIt it(graph); it != INVALID; ++it) { - for (int i = 0; i < (int)node_map_writers.size(); ++i) { - node_map_writers[i].second->write(os, it); - } - os << std::endl; - } - - } - - void writeEdgeSet(WriterBase* nodeWriter, - WriterBase* & edgeWriter) { - if (edge_map_writers.size() == 0) return; - if (nodeWriter == 0) { - throw DataFormatError("Cannot find node id map"); - } - os << "@edgeset" << std::endl; - os << "\t\t"; - for (int i = 0; i < (int)edge_map_writers.size(); ++i) { - const std::string& id = edge_map_writers[i].first; - os << id << '\t'; - if (WriterTraits::idMapName(id) && edgeWriter == 0) { - edgeWriter = edge_map_writers[i].second; - } - } - os << std::endl; - for (EdgeIt it(graph); it != INVALID; ++it) { - nodeWriter->write(os, graph.source(it)); - nodeWriter->write(os, graph.target(it)); - for (int i = 0; i < (int)edge_map_writers.size(); ++i) { - edge_map_writers[i].second->write(os, it); - } - os << std::endl; - } - } - - void writeNodes(WriterBase* nodeWriter) { - if (node_writers.size() == 0) return; - if (nodeWriter == 0) { - throw DataFormatError("Cannot find node id map"); - } - os << "@nodes" << std::endl; - for (int i = 0; i < (int)node_writers.size(); ++i) { - os << node_writers[i].first << '\t'; - nodeWriter->write(os, node_writers[i].second); - os << std::endl; - } - } - - void writeEdges(WriterBase* edgeWriter) { - if (edge_writers.size() == 0) return; - if (edgeWriter == 0) { - throw DataFormatError("Cannot find node id map"); - } - os << "@edges" << std::endl; - for (int i = 0; i < (int)edge_writers.size(); ++i) { - os << edge_writers[i].first << '\t'; - edgeWriter->write(os, edge_writers[i].second); - os << std::endl; - } - } - - void writeGUI() { - if (gui_writer) { - os << "@gui" << std::endl; - gui_writer->write(os); - } - } - - - - typedef std::vector< std::pair*> > - NodeMapWriters; - NodeMapWriters node_map_writers; - - typedef std::vector< std::pair*> > - EdgeMapWriters; - EdgeMapWriters edge_map_writers; - - typedef std::vector > NodeWriters; - NodeWriters node_writers; - - typedef std::vector > EdgeWriters; - EdgeWriters edge_writers; - - GUIWriter* gui_writer; - - std::ostream& os; const Graph& graph; + NodeSetWriter nodeset_writer; + EdgeSetWriter edgeset_writer; + + NodeWriter node_writer; + EdgeWriter edge_writer; + + AttributeWriter attribute_writer; }; + /// \brief Write a graph to the output. /// /// Write a graph to the output. diff -r 892c29484414 -r d2d1f8fa187b src/lemon/lemon_reader.h --- a/src/lemon/lemon_reader.h Mon May 09 11:24:26 2005 +0000 +++ b/src/lemon/lemon_reader.h Wed May 11 11:50:13 2005 +0000 @@ -30,16 +30,41 @@ #include #include -#include "item_reader.h" +#include namespace lemon { - /// \addtogroup io_group - /// @{ - + /// \ingroup io_group /// \brief Lemon Format reader 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 read 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 LemonReader::SectionReader class + /// what defines the interface of a SectionReader. The SectionReader + /// has the \c header() member function what get a header line string and + /// decides if it want to process the next section. Several SectionReaders + /// can be attached to an LemonReader and the first attached what can + /// process the section will be used. Its \c read() member will called + /// with a stream contains the section. From this stream the empty lines + /// and comments are filtered out. + /// + /// \relates GraphReader + /// \relates NodeSetReader + /// \relates EdgeSetReader + /// \relates NodesReader + /// \relates EdgesReader + /// \relates AttributeReader class LemonReader { private: @@ -185,24 +210,55 @@ public: + /// \brief Abstract base class for reading a section. + /// + /// This class has an \c header() member function what get a + /// header line string and decides if it want to process the next + /// section. Several SectionReaders can be attached to an LemonReader + /// and the first attached what can process the section will be used. + /// Its \c read() member will called with a stream contains the section. + /// From this stream the empty lines and comments are filtered out. class SectionReader { - public: - /// \e + friend class LemonReader; + protected: + /// \brief Constructor for SectionReader. + /// + /// Constructor for SectionReader. It attach this reader to + /// the given LemonReader. + SectionReader(LemonReader& reader) { + reader.attach(*this); + } + + /// \brief Gives back true when the SectionReader can process + /// the section with the given header line. + /// + /// It gives back true when the SectionReader can process + /// the section with the given header line. virtual bool header(const std::string& line) = 0; - /// \e + + /// \brief Reader function of the section. + /// + /// It reads the content of the section. virtual void read(std::istream& is) = 0; }; - /// \e + /// \brief Constructor for LemonReader. + /// + /// Constructor for LemonReader which reads from the given stream. LemonReader(std::istream& _is) : is(&_is), own_is(false) {} + /// \brief Constructor for LemonReader. + /// + /// Constructor for LemonReader which reads from the given file. LemonReader(const std::string& filename) : is(0), own_is(true) { is = new std::ifstream(filename.c_str()); } - + /// \brief Desctructor for LemonReader. + /// + /// Desctructor for LemonReader. ~LemonReader() { if (own_is) { delete is; @@ -213,23 +269,14 @@ LemonReader(const LemonReader&); void operator=(const LemonReader&); - public: - - /// \e void attach(SectionReader& reader) { readers.push_back(&reader); } - /// \e - void detach(SectionReader& reader) { - std::vector::iterator it = - std::find(readers.begin(), readers.end(), &reader); - if (it != readers.end()) { - readers.erase(it); - } - } - - /// \e + public: + /// \brief Executes the LemonReader. + /// + /// It executes the LemonReader. void run() { int line_num = 0; std::string line; @@ -264,10 +311,20 @@ }; + /// \brief Helper class for implementing the common SectionReaders. + /// + /// Helper class for implementing the common SectionReaders. + class CommonSectionReaderBase : public LemonReader::SectionReader { + typedef LemonReader::SectionReader Parent; + protected: + + /// \brief Constructor for CommonSectionReaderBase. + /// + /// Constructor for CommonSectionReaderBase. It attach this reader to + /// the given LemonReader. + CommonSectionReaderBase(LemonReader& _reader) + : Parent(_reader) {} - /// \e - class CommonSectionReaderBase : public LemonReader::SectionReader { - protected: template class ReaderBase; @@ -433,25 +490,25 @@ }; template - class ResolverReaderBase { + class IdReaderBase { public: typedef _Item Item; - virtual Item resolve(std::istream& is) const = 0; + virtual Item read(std::istream& is) const = 0; }; - template - class ResolverReader : public ResolverReaderBase<_Item> { + template + class IdReader : public IdReaderBase<_Item> { public: typedef _Item Item; - typedef _Resolver Resolver; + typedef _BoxedIdReader BoxedIdReader; + + const BoxedIdReader& boxedIdReader; - const Resolver& resolver; + IdReader(const BoxedIdReader& _boxedIdReader) + : boxedIdReader(_boxedIdReader) {} - ResolverReader(const Resolver& _resolver) - : resolver(_resolver) {} - - virtual Item resolve(std::istream& is) const { - return resolver.resolve(is); + virtual Item read(std::istream& is) const { + return boxedIdReader.readId(is); } }; @@ -479,7 +536,23 @@ }; - + /// \ingroup io_group + /// \brief SectionReader for reading 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 readId() member will read a value from the given stream it will + /// give back that node which is mapped to this value. + /// + /// \relates LemonReader template class NodeSetReader : public CommonSectionReaderBase { typedef CommonSectionReaderBase Parent; @@ -490,13 +563,21 @@ typedef typename Graph::Node Item; typedef typename Traits::Skipper DefaultSkipper; + /// \brief Constructor. + /// + /// Constructor for NodeSetReader. It creates the NodeSetReader and + /// attach it into the given LemonReader. The nodeset reader will + /// add the readed nodes to the given Graph. The reader will read + /// the section when the \c section_id and the \c _id are the same. NodeSetReader(LemonReader& _reader, Graph& _graph, const std::string& _id = std::string(), - const DefaultSkipper& _defreader = DefaultSkipper()) - : graph(_graph), id(_id), skipper(_defreader) { - _reader.attach(*this); - } + const DefaultSkipper& _skipper = DefaultSkipper()) + : Parent(_reader), graph(_graph), id(_id), skipper(_skipper) {} + + /// \brief Destructor. + /// + /// Destructor for NodeSetReader. virtual ~NodeSetReader() { for (typename MapReaders::iterator it = readers.begin(); it != readers.end(); ++it) { @@ -550,7 +631,13 @@ return *this; } - /// \e + protected: + + /// \brief Gives back true when the SectionReader can process + /// the section with the given header line. + /// + /// It gives back true when the header line starts with \c @nodeset, + /// and the header line's id and the nodeset's id are the same. virtual bool header(const std::string& line) { std::istringstream ls(line); std::string command; @@ -559,7 +646,9 @@ return command == "@nodeset" && name == id; } - /// \e + /// \brief Reader function of the section. + /// + /// It reads the content of the section. virtual void read(std::istream& is) { std::vector* > index; std::string line; @@ -587,11 +676,21 @@ } } - bool isResolver() const { + public: + + /// \brief Returns true if the nodeset can give back the node by its id. + /// + /// Returns true if the nodeset can give back the node by its id. + /// It is possible only if an "id" named map was read. + bool isIdReader() const { return inverter.get() != 0; } - typename Graph::Node resolve(std::istream& is) const { + /// \brief Gives back the node by its id. + /// + /// It reads an id from the stream and gives back which node belongs to + /// it. It is possible only if there was read an "id" named map. + typename Graph::Node readId(std::istream& is) const { return inverter->read(is); } @@ -607,9 +706,27 @@ std::auto_ptr > inverter; }; - - - /// \e + /// \ingroup io_group + /// \brief SectionReader for reading 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 node in the nodeset. The + /// line contains the two 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 readId() member will read a value from the given stream it will + /// give back that edge which is mapped to this value. + /// + /// The edgeset reader needs a node id reader to identify which nodes + /// have to be connected. If a NodeSetReader reads an "id" named map, + /// it will be able to resolve the nodes by ids. + /// + /// \relates LemonReader template class EdgeSetReader : public CommonSectionReaderBase { typedef CommonSectionReaderBase Parent; @@ -620,17 +737,26 @@ typedef typename Graph::Edge Item; typedef typename Traits::Skipper DefaultSkipper; - template + /// \brief Constructor. + /// + /// Constructor for EdgeSetReader. It creates the EdgeSetReader and + /// attach it into the given LemonReader. The edgeset reader will + /// add the readed edges to the given Graph. It will use the given + /// node id reader to read the source and target nodes of the edges. + /// The reader will read the section only if the \c _id and the + /// \c edgset_id are the same. + template EdgeSetReader(LemonReader& _reader, Graph& _graph, - const Resolver& _nodeResolver, + const NodeIdReader& _nodeIdReader, const std::string& _id = std::string(), - const DefaultSkipper& _defreader = DefaultSkipper()) - : graph(_graph), id(_id), skipper(_defreader), - nodeResolver(new ResolverReader - (_nodeResolver)) { - _reader.attach(*this); - } + const DefaultSkipper& _skipper = DefaultSkipper()) + : Parent(_reader), graph(_graph), id(_id), skipper(_skipper), + nodeIdReader(new IdReader + (_nodeIdReader)) {} + /// \brief Destructor. + /// + /// Destructor for EdgeSetReader. virtual ~EdgeSetReader() { for (typename MapReaders::iterator it = readers.begin(); it != readers.end(); ++it) { @@ -644,18 +770,18 @@ public: - /// \brief Add a new node map reader command for the reader. + /// \brief Add a new edge map reader command for the reader. /// - /// Add a new node map reader command for the reader. + /// Add a new edge map reader command for the reader. template EdgeSetReader& readMap(std::string name, Map& map) { return readMap, Map>(name, map); } - /// \brief Add a new node map reader command for the reader. + /// \brief Add a new edge map reader command for the reader. /// - /// Add a new node map reader command for the reader. + /// Add a new edge map reader command for the reader. template EdgeSetReader& readMap(std::string name, Map& map, const Reader& reader = Reader()) { @@ -669,9 +795,9 @@ return *this; } - /// \brief Add a new node map skipper command for the reader. + /// \brief Add a new edge map skipper command for the reader. /// - /// Add a new node map skipper command for the reader. + /// Add a new edge map skipper command for the reader. template EdgeSetReader& skipMap(std::string name, const Reader& reader = Reader()) { @@ -684,7 +810,13 @@ return *this; } - /// \e + protected: + + /// \brief Gives back true when the SectionReader can process + /// the section with the given header line. + /// + /// It gives back true when the header line starts with \c @edgeset, + /// and the header line's id and the edgeset's id are the same. virtual bool header(const std::string& line) { std::istringstream ls(line); std::string command; @@ -693,7 +825,9 @@ return command == "@edgeset" && name == id; } - /// \e + /// \brief Reader function of the section. + /// + /// It reads the content of the section. virtual void read(std::istream& is) { std::vector* > index; std::string line; @@ -714,8 +848,8 @@ } while (getline(is, line)) { std::istringstream ls(line); - typename Graph::Node from = nodeResolver->resolve(ls); - typename Graph::Node to = nodeResolver->resolve(ls); + typename Graph::Node from = nodeIdReader->read(ls); + typename Graph::Node to = nodeIdReader->read(ls); typename Graph::Edge edge = graph.addEdge(from, to); for (int i = 0; i < (int)index.size(); ++i) { index[i]->read(ls, edge); @@ -723,11 +857,21 @@ } } - bool isResolver() const { + public: + + /// \brief Returns true if the edgeset can give back the edge by its id. + /// + /// Returns true if the edgeset can give back the edge by its id. + /// It is possible only if an "id" named map was read. + bool isIdReader() const { return inverter.get() != 0; } - typename Graph::Edge resolve(std::istream& is) { + /// \brief Gives back the edge by its id. + /// + /// It reads an id from the stream and gives back which edge belongs to + /// it. It is possible only if there was read an "id" named map. + typename Graph::Edge readId(std::istream& is) const { return inverter->read(is); } @@ -741,23 +885,220 @@ SkipReader skipper; std::auto_ptr > inverter; - std::auto_ptr > nodeResolver; + std::auto_ptr > nodeIdReader; }; + /// \ingroup io_group + /// \brief SectionReader for reading 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 name of the node + /// and then the node id. + /// + /// \relates LemonReader + template + class NodeReader : public CommonSectionReaderBase { + typedef CommonSectionReaderBase Parent; + typedef _Graph Graph; + typedef typename Graph::Node Item; + public: + + /// \brief Constructor. + /// + /// Constructor for NodeReader. It creates the NodeReader and + /// attach it into the given LemonReader. It will use the given + /// node id reader to give back the nodes. The reader will read the + /// section only if the \c _id and the \c nodes_id are the same. + template + NodeReader(LemonReader& _reader, const _IdReader& _idReader, + const std::string& _id = std::string()) + : Parent(_reader), id(_id), + idReader(new IdReader(_idReader)) {} - /// \e + /// \brief Destructor. + /// + /// Destructor for NodeReader. + virtual ~NodeReader() {} + + private: + NodeReader(const NodeReader&); + void operator=(const NodeReader&); + + public: + + /// \brief Add a node reader command for the NodeReader. + /// + /// Add a node reader command for the NodeReader. + void readNode(const std::string& name, Item& item) { + if (readers.find(name) != readers.end()) { + ErrorMessage msg; + msg << "Multiple read rule for node: " << name; + throw IOParameterError(msg.message()); + } + readers.insert(make_pair(name, &item)); + } + + protected: + + /// \brief Gives back true when the SectionReader can process + /// the section with the given header line. + /// + /// It gives back true when the header line start with \c @nodes, + /// and the header line's id and the reader's id are the same. + virtual bool header(const std::string& line) { + std::istringstream ls(line); + std::string command; + std::string name; + ls >> command >> name; + return command == "@nodes" && name == id; + } + + /// \brief Reader function of the section. + /// + /// It reads the content of the section. + virtual void read(std::istream& is) { + std::string line; + while (getline(is, line)) { + std::istringstream ls(line); + std::string id; + ls >> id; + typename ItemReaders::iterator it = readers.find(id); + if (it != readers.end()) { + *(it->second) = idReader->read(ls); + } + } + } + + private: + + std::string id; + + typedef std::map ItemReaders; + ItemReaders readers; + std::auto_ptr > idReader; + }; + + /// \ingroup io_group + /// \brief SectionReader for reading 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 name of the edge + /// and then the edge id. + /// + /// \relates LemonReader + template + class EdgeReader : public CommonSectionReaderBase { + typedef CommonSectionReaderBase Parent; + typedef _Graph Graph; + typedef typename Graph::Edge Item; + public: + + /// \brief Constructor. + /// + /// Constructor for EdgeReader. It creates the EdgeReader and + /// attach it into the given LemonReader. It will use the given + /// edge id reader to give back the edges. The reader will read the + /// section only if the \c _id and the \c nodes_id are the same. + template + EdgeReader(LemonReader& _reader, const _IdReader& _idReader, + const std::string& _id = std::string()) + : Parent(_reader), id(_id), + idReader(new IdReader(_idReader)) {} + + /// \brief Destructor. + /// + /// Destructor for EdgeReader. + virtual ~EdgeReader() {} + private: + EdgeReader(const EdgeReader&); + void operator=(const EdgeReader&); + + public: + + /// \brief Add an edge reader command for the EdgeReader. + /// + /// Add an edge reader command for the EdgeReader. + void readEdge(const std::string& name, Item& item) { + if (readers.find(name) != readers.end()) { + ErrorMessage msg; + msg << "Multiple read rule for edge: " << name; + throw IOParameterError(msg.message()); + } + readers.insert(make_pair(name, &item)); + } + + protected: + + /// \brief Gives back true when the SectionReader can process + /// the section with the given header line. + /// + /// It gives back true when the header line start with \c @edges, + /// and the header line's id and the reader's id are the same. + virtual bool header(const std::string& line) { + std::istringstream ls(line); + std::string command; + std::string name; + ls >> command >> name; + return command == "@edges" && name == id; + } + + /// \brief Reader function of the section. + /// + /// It reads the content of the section. + virtual void read(std::istream& is) { + std::string line; + while (getline(is, line)) { + std::istringstream ls(line); + std::string id; + ls >> id; + typename ItemReaders::iterator it = readers.find(id); + if (it != readers.end()) { + *(it->second) = idReader->read(ls); + } + } + } + + private: + + std::string id; + + typedef std::map ItemReaders; + ItemReaders readers; + std::auto_ptr > idReader; + }; + + /// \ingroup io_group + /// \brief SectionReader 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 an attribute and then a the value for the id. + /// + /// \relates LemonReader template class AttributeReader : public CommonSectionReaderBase { typedef CommonSectionReaderBase Parent; typedef _Traits Traits; public: - /// \e + /// \brief Constructor. + /// + /// Constructor for AttributeReader. It creates the AttributeReader and + /// attach it into the given LemonReader. The reader process a section + /// only if the \c section_id and the \c _id are the same. AttributeReader(LemonReader& _reader, - const std::string& _id = std::string()) : id(_id) { - _reader.attach(*this); - } + const std::string& _id = std::string()) + : Parent(_reader), id(_id) {} - /// \e + /// \brief Destructor. + /// + /// Destructor for AttributeReader. virtual ~AttributeReader() { for (typename Readers::iterator it = readers.begin(); it != readers.end(); ++it) { @@ -770,14 +1111,18 @@ void operator=(AttributeReader&); public: - /// \e + /// \brief Add an attribute reader command for the reader. + /// + /// Add an attribute reader command for the reader. template AttributeReader& readAttribute(const std::string& id, Value& value) { return readAttribute > (id, value); } - /// \e + /// \brief Add an attribute reader command for the reader. + /// + /// Add an attribute reader command for the reader. template AttributeReader& readAttribute(const std::string& name, Value& value, const Reader& reader = Reader()) { @@ -791,7 +1136,13 @@ return *this; } - /// \e + protected: + + /// \brief Gives back true when the SectionReader can process + /// the section with the given header line. + /// + /// It gives back true when the header line start with \c @attributes, + /// and the header line's id and the attributeset's id are the same. bool header(const std::string& line) { std::istringstream ls(line); std::string command; @@ -800,7 +1151,9 @@ return command == "@attributes" && name == id; } - /// \e + /// \brief Reader function of the section. + /// + /// It reads the content of the section. void read(std::istream& is) { std::string line; while (getline(is, line)) { @@ -818,160 +1171,9 @@ std::string id; typedef std::map Readers; - Readers readers; - + Readers readers; }; - template - class NodeReader : public CommonSectionReaderBase { - typedef CommonSectionReaderBase Parent; - typedef _Graph Graph; - typedef typename Graph::Node Item; - public: - - template - NodeReader(LemonReader& _reader, const Resolver& _resolver, - const std::string& _id = std::string()) - : id(_id), resolver(new ResolverReader - (_resolver)) { - _reader.attach(*this); - } - virtual ~NodeReader() {} - - private: - NodeReader(const NodeReader&); - void operator=(const NodeReader&); - - public: - - void readNode(const std::string& name, Item& item) { - if (readers.find(name) != readers.end()) { - ErrorMessage msg; - msg << "Multiple read rule for node: " << name; - throw IOParameterError(msg.message()); - } - readers.insert(make_pair(name, &item)); - } - - virtual bool header(const std::string& line) { - std::istringstream ls(line); - std::string command; - std::string name; - ls >> command >> name; - return command == "@nodes" && name == id; - } - - virtual void read(std::istream& is) { - std::string line; - while (getline(is, line)) { - std::istringstream ls(line); - std::string id; - ls >> id; - typename ItemReaders::iterator it = readers.find(id); - if (it != readers.end()) { - *(it->second) = resolver->resolve(ls); - } - } - } - - private: - - std::string id; - - typedef std::map ItemReaders; - ItemReaders readers; - std::auto_ptr > resolver; - }; - - template - class EdgeReader : public CommonSectionReaderBase { - typedef CommonSectionReaderBase Parent; - typedef _Graph Graph; - typedef typename Graph::Edge Item; - public: - - template - EdgeReader(LemonReader& _reader, const Resolver& _resolver, - const std::string& _id = std::string()) - : id(_id), resolver(new ResolverReader - (_resolver)) { - _reader.attach(*this); - } - - virtual ~EdgeReader() {} - private: - EdgeReader(const EdgeReader&); - void operator=(const EdgeReader&); - - public: - - void readEdge(const std::string& name, Item& item) { - if (readers.find(name) != readers.end()) { - ErrorMessage msg; - msg << "Multiple read rule for edge: " << name; - throw IOParameterError(msg.message()); - } - readers.insert(make_pair(name, &item)); - } - - - virtual bool header(const std::string& line) { - std::istringstream ls(line); - std::string command; - std::string name; - ls >> command >> name; - return command == "@nodes" && name == id; - } - - virtual void read(std::istream& is) { - std::string line; - while (getline(is, line)) { - std::istringstream ls(line); - std::string id; - ls >> id; - typename ItemReaders::iterator it = readers.find(id); - if (it != readers.end()) { - *(it->second) = resolver->resolve(ls); - } - } - } - - private: - - std::string id; - - typedef std::map ItemReaders; - ItemReaders readers; - std::auto_ptr > resolver; - }; - - /// \e - class PrintReader : public LemonReader::SectionReader { - typedef LemonReader::SectionReader Parent; - public: - - /// \e - PrintReader(LemonReader& reader) { - reader.attach(*this); - } - - /// \e - bool header(const std::string& line) { - std::cout << "Asked header: " << line << std::endl; - return true; - } - - /// \e - void read(std::istream& is) { - std::string line; - while (std::getline(is, line)) { - std::cout << line << std::endl; - } - } - - }; - - /// @} } #endif 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