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