[Lemon-commits] [lemon_svn] deba: r1875 - in hugo/trunk/src/lemon: . bits
Lemon SVN
svn at lemon.cs.elte.hu
Mon Nov 6 20:48:23 CET 2006
Author: deba
Date: Mon May 9 13:24:26 2005
New Revision: 1875
Added:
hugo/trunk/src/lemon/bits/item_reader.h
hugo/trunk/src/lemon/lemon_reader.h
- copied, changed from r1862, /hugo_loc/work/deba/lemon_reader.h
Modified:
hugo/trunk/src/lemon/Makefile.am
hugo/trunk/src/lemon/graph_reader.h
Log:
New graph reader interface.
Modified: hugo/trunk/src/lemon/Makefile.am
==============================================================================
--- hugo/trunk/src/lemon/Makefile.am (original)
+++ hugo/trunk/src/lemon/Makefile.am Mon May 9 13:24:26 2005
@@ -52,6 +52,7 @@
xy.h \
concept_check.h \
utility.h \
+ lemon_reader.h \
graph_reader.h \
graph_writer.h \
bits/alteration_notifier.h \
@@ -64,7 +65,8 @@
bits/extendable_graph_extender.h \
bits/clearable_graph_extender.h \
bits/erasable_graph_extender.h \
- bits/undir_graph_extender.h
+ bits/undir_graph_extender.h \
+ bits/item_reader.h
noinst_HEADERS = \
concept/graph.h \
Added: hugo/trunk/src/lemon/bits/item_reader.h
==============================================================================
--- (empty file)
+++ hugo/trunk/src/lemon/bits/item_reader.h Mon May 9 13:24:26 2005
@@ -0,0 +1,395 @@
+/* -*- 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 reader bits for lemon input.
+
+#ifndef LEMON_BITS_ITEM_READER_H
+#define LEMON_BITS_ITEM_READER_H
+
+#include <iostream>
+#include <string>
+
+#include <vector>
+#include <deque>
+#include <list>
+#include <set>
+
+namespace lemon {
+
+ template <typename Value>
+ class DefaultReader;
+
+ /// \ingroup io_group
+ ///
+ /// \brief Reader class for quoted strings.
+ ///
+ /// Reader class for quoted strings. It can process the escape
+ /// sequences in the string.
+ ///
+ /// \author Balazs Dezso
+ class QuotedStringReader {
+ public:
+ /// \brief The value type of reader.
+ ///
+ /// The value type of reader.
+ typedef std::string Value;
+
+ /// \brief Constructor for the reader.
+ ///
+ /// Constructor for the reader. If the given parameter is true
+ /// the reader processes the escape sequences.
+ QuotedStringReader(bool _escaped = true)
+ : escaped(_escaped) {}
+
+ /// \brief Reads a quoted string from the given stream.
+ ///
+ /// Reads a quoted string from the given stream.
+ void read(std::istream& is, std::string& value) const {
+ char c;
+ value.clear();
+ is >> std::ws;
+ if (!is.get(c) || c != '\"')
+ throw DataFormatError("Quoted string format error");
+ while (is.get(c) && c != '\"') {
+ if (escaped && c == '\\') {
+ value += readEscape(is);
+ } else {
+ value += c;
+ }
+ }
+ if (!is) throw DataFormatError("Quoted string format error");
+ }
+
+ private:
+
+ static char readEscape(std::istream& is) {
+ char c;
+ switch (is.get(c), c) {
+ case '\\':
+ return '\\';
+ case '\"':
+ return '\"';
+ case '\'':
+ return '\'';
+ case '\?':
+ return '\?';
+ case 'a':
+ return '\a';
+ case 'b':
+ return '\b';
+ case 'f':
+ return '\f';
+ case 'n':
+ return '\n';
+ case 'r':
+ return '\r';
+ case 't':
+ return '\t';
+ case 'v':
+ return '\v';
+ case 'x':
+ {
+ int code;
+ if (!is.get(c) || !isHex(c))
+ throw DataFormatError("Escape format error");
+ else if (code = valueHex(c), !is.get(c) || !isHex(c)) is.putback(c);
+ else code = code * 16 + valueHex(c);
+ return code;
+ }
+ default:
+ {
+ int code;
+ if (!isOct(c))
+ throw DataFormatError("Escape format error");
+ else if (code = valueOct(c), !is.get(c) || !isOct(c))
+ is.putback(c);
+ else if (code = code * 8 + valueOct(c), !is.get(c) || !isOct(c))
+ is.putback(c);
+ else code = code * 8 + valueOct(c);
+ return code;
+ }
+ }
+ }
+
+ static bool isOct(char c) {
+ return '0' <= c && c <='7';
+ }
+
+ static int valueOct(char c) {
+ return c - '0';
+ }
+
+ static bool isHex(char c) {
+ return ('0' <= c && c <= '9') ||
+ ('a' <= c && c <= 'z') ||
+ ('A' <= c && c <= 'Z');
+ }
+
+ static int valueHex(char c) {
+ if ('0' <= c && c <= '9') return c - '0';
+ if ('a' <= c && c <= 'z') return c - 'a' + 10;
+ return c - 'A' + 10;
+ }
+
+ bool escaped;
+ };
+
+ /// \ingroup io_group
+ /// \brief Reader for standard containers.
+ ///
+ /// Reader for back insertable 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 _ItemReader = DefaultReader<typename _Container::value_type>
+ >
+ class PushBackReader {
+ public:
+ typedef _Container Value;
+ typedef _ItemReader ItemReader;
+
+ private:
+
+ ItemReader item_reader;
+
+ public:
+
+ /// \brief Reads the values into the container from the given stream.
+ ///
+ /// Reads the values into the container from the given stream.
+ void read(std::istream& is, Value& value) const {
+ char c;
+ if (!(is >> c) || c != '(')
+ throw DataFormatError("PushBackReader format error");
+ while (is >> c && c != ')') {
+ is.putback(c);
+ typename ItemReader::Value item;
+ item_reader.read(is, item);
+ value.push_back(item);
+ }
+ if (!is) throw DataFormatError("PushBackReader format error");
+ is.putback(c);
+ }
+
+ };
+
+ /// \ingroup io_group
+ ///
+ /// \brief Reader for standard containers.
+ ///
+ /// Reader for insertable 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 _ItemReader = DefaultReader<typename _Container::value_type>
+ >
+ class InsertReader {
+ public:
+ typedef _Container Value;
+ typedef _ItemReader ItemReader;
+
+ private:
+
+ ItemReader item_reader;
+
+ public:
+
+ /// \brief Reads the values into the container from the given stream.
+ ///
+ /// Reads the values into the container from the given stream.
+ void read(std::istream& is, Value& value) const {
+ char c;
+ if (!(is >> c) || c != '(')
+ throw DataFormatError("InsertReader format error");
+ while (is >> c && c != ')') {
+ is.putback(c);
+ typename ItemReader::Value item;
+ item_reader.read(is, item);
+ value.insert(item);
+ }
+ if (!is) throw DataFormatError("PushBackReader format error");
+ is.putback(c);
+ }
+
+ };
+
+ /// \ingroup io_group
+ /// \brief Reader for parsed string.
+ ///
+ /// Reader for parsed strings. You can give the open and close
+ /// parse characters.
+ ///
+ /// \author Balazs Dezso
+ class ParsedStringReader {
+ public:
+ typedef std::string Value;
+
+ /// \brief Constructor.
+ ///
+ /// Constructor for ParsedStringReader. You can give as parameter
+ /// the open and close parse characters.
+ ParsedStringReader(char _open = '(', char _close = ')')
+ : open(_open), close(_close) {}
+
+
+ /// \brief Reads the parsed string from the given stream.
+ ///
+ /// Reads the parsed string from the given stream.
+ void read(std::istream& is, Value& value) const {
+ char c;
+ if (!(is >> c) || c != open) {
+ throw DataFormatError("ParsedStringReader format error");
+ }
+ value += c;
+ int counter = 1;
+ while (counter > 0 && is >> c) {
+ if (c == close) {
+ --counter;
+ } else if (c == open) {
+ ++counter;
+ }
+ value += c;
+ }
+ if (!is) {
+ throw DataFormatError("ParsedStrinReader format error");
+ }
+ }
+
+ private:
+ char open, close;
+
+ };
+
+ /// \ingroup io_group
+ /// \brief Reader for read the whole line.
+ ///
+ /// Reader for read the whole line.
+ ///
+ /// \author Balazs Dezso
+ class LineReader {
+ public:
+ typedef std::string Value;
+
+ /// \brief Constructor.
+ ///
+ /// Constructor for the LineReader. If the given parameter is
+ /// true then the spaces before the first not space character are
+ /// skipped.
+ LineReader(bool _skipSpaces = true) : skipSpaces(_skipSpaces) {}
+
+ /// \brief Reads the line from the given stream.
+ ///
+ /// Reads the line from the given stream.
+ void read(std::istream& is, Value& value) {
+ if (skipSpaces) is >> std::ws;
+ if (!getline(is, value)) {
+ throw DataFormatError("LineReader forma error");
+ }
+ }
+ private:
+ bool skipSpaces;
+ };
+
+ /// \ingroup io_group
+ ///
+ /// \brief The default item reader template class.
+ ///
+ /// The default item reader template class. If some section reader
+ /// needs to read a value from a stream it will give the default way for it.
+ ///
+ /// \author Balazs Dezso
+ template <typename _Value>
+ class DefaultReader {
+ public:
+ /// The value type.
+ typedef _Value Value;
+ /// \brief Reads a value from the given stream.
+ ///
+ /// Reads a value from the given stream.
+ void read(std::istream& is, Value& value) const {
+ if (!(is >> value))
+ throw DataFormatError("DefaultReader format error");
+ }
+ };
+
+ template <typename Item>
+ class DefaultReader<std::vector<Item> >
+ : public PushBackReader<std::vector<Item> > {};
+
+ template <typename Item>
+ class DefaultReader<std::deque<Item> >
+ : public PushBackReader<std::deque<Item> > {};
+
+ template <typename Item>
+ class DefaultReader<std::list<Item> >
+ : public PushBackReader<std::list<Item> > {};
+
+ template <typename Item>
+ class DefaultReader<std::set<Item> >
+ : public InsertReader<std::set<Item> > {};
+
+ template <typename Item>
+ class DefaultReader<std::multiset<Item> >
+ : public InsertReader<std::multiset<Item> > {};
+
+ /// \ingroup io_group
+ class DefaultSkipper {
+ public:
+ typedef std::string Value;
+
+ void read(std::istream& is, Value& value) const {
+ char c;
+ if (!(is >> c)) return;
+ is.putback(c);
+ switch (c) {
+ case '\"':
+ QuotedStringReader().read(is, value);
+ break;
+ case '(':
+ ParsedStringReader().read(is, value);
+ break;
+ default:
+ DefaultReader<std::string>().read(is, value);
+ break;
+ }
+ }
+ };
+
+ /// \brief Standard ReaderTraits for the GraphReader class.
+ ///
+ /// Standard ReaderTraits for the GraphReader class.
+ /// It defines standard reading method for all type of value.
+ /// \author Balazs Dezso
+ struct DefaultReaderTraits {
+
+ template <typename _Value>
+ struct Reader : DefaultReader<_Value> {};
+
+ typedef DefaultSkipper Skipper;
+
+ };
+
+}
+
+#endif
Modified: hugo/trunk/src/lemon/graph_reader.h
==============================================================================
--- hugo/trunk/src/lemon/graph_reader.h (original)
+++ hugo/trunk/src/lemon/graph_reader.h Mon May 9 13:24:26 2005
@@ -22,173 +22,17 @@
#define LEMON_GRAPH_READER_H
#include <iostream>
-#include <sstream>
-
-#include <map>
-#include <vector>
-
-#include <memory>
#include <lemon/error.h>
-
+#include <lemon/lemon_reader.h>
namespace lemon {
/// \addtogroup io_group
/// @{
- /// \brief Standard ReaderTraits for the GraphReader class.
- ///
- /// Standard ReaderTraits for the GraphReader class.
- /// It defines standard reading method for all type of value.
- /// \author Balazs Dezso
- struct DefaultReaderTraits {
-
- /// \brief Template class for reading an value.
- ///
- /// Template class for reading an value.
- /// \author Balazs Dezso
- template <typename _Value>
- struct Reader {
- /// The value type.
- typedef _Value Value;
- /// \brief Reads a value from the given stream.
- ///
- /// Reads a value from the given stream.
- void read(std::istream& is, Value& value) {
- if (!(is >> value))
- throw DataFormatError("Default reader format exception");
- }
- };
-
- /// \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";
- }
-
- /// The reader class for the not needed maps.
- typedef Reader<std::string> DefaultReader;
-
- };
-
- /// \brief Reader class for quoted strings.
- ///
- /// Reader class for quoted strings. It can process the escape
- /// sequences in the string.
- /// \author Balazs Dezso
- class QuotedStringReader {
- public:
- typedef std::string Value;
-
- /// \brief Constructor for the reader.
- ///
- /// Constructor for the reader. If the given parameter is true
- /// the reader processes the escape sequences.
- QuotedStringReader(bool _escaped = true) : escaped(_escaped) {}
-
- /// \brief Reads a quoted string from the given stream.
- ///
- /// Reads a quoted string from the given stream.
- void read(std::istream& is, std::string& value) {
- char c;
- value.clear();
- is >> std::ws;
- if (!is.get(c) || c != '\"')
- throw DataFormatError("Quoted string format error");
- while (is.get(c) && c != '\"') {
- if (escaped && c == '\\') {
- value += readEscape(is);
- } else {
- value += c;
- }
- }
- if (!is) throw DataFormatError("Quoted string format error");
- }
-
- private:
-
- static char readEscape(std::istream& is) {
- char c;
- switch (is.get(c), c) {
- case '\\':
- return '\\';
- case '\"':
- return '\"';
- case '\'':
- return '\'';
- case '\?':
- return '\?';
- case 'a':
- return '\a';
- case 'b':
- return '\b';
- case 'f':
- return '\f';
- case 'n':
- return '\n';
- case 'r':
- return '\r';
- case 't':
- return '\t';
- case 'v':
- return '\v';
- case 'x':
- {
- int code;
- if (!is.get(c) || !isHex(c))
- throw DataFormatError("Escape format error");
- else if (code = valueHex(c), !is.get(c) || !isHex(c)) is.putback(c);
- else code = code * 16 + valueHex(c);
- return code;
- }
- default:
- {
- int code;
- if (!isOct(c))
- throw DataFormatError("Escape format error");
- else if (code = valueOct(c), !is.get(c) || !isOct(c))
- is.putback(c);
- else if (code = code * 8 + valueOct(c), !is.get(c) || !isOct(c))
- is.putback(c);
- else code = code * 8 + valueOct(c);
- return code;
- }
- }
- }
-
- static bool isOct(char c) {
- return '0' <= c && c <='7';
- }
-
- static int valueOct(char c) {
- return c - '0';
- }
-
- static bool isHex(char c) {
- return ('0' <= c && c <= '9') ||
- ('a' <= c && c <= 'z') ||
- ('A' <= c && c <= 'Z');
- }
-
- static int valueHex(char c) {
- if ('0' <= c && c <= '9') return c - '0';
- if ('a' <= c && c <= 'z') return c - 'a' + 10;
- return c - 'A' + 10;
- }
-
- bool escaped;
- };
-
- class GUIReader {
- public:
- virtual void read(std::istream& is) = 0;
- };
-
/// \brief The graph reader class.
///
- ///
/// The given file format may contain several maps and labeled nodes or
/// edges.
///
@@ -229,8 +73,8 @@
/// reader.readEdgeMap("label", labelMap);
/// \endcode
///
- /// With \c readNode() and \c readEdge() functions you can read labeled Nodes
- /// and Edges.
+ /// With \c readNode() and \c readEdge() functions you can read
+ /// labeled Nodes and Edges.
///
/// \code
/// reader.readNode("source", sourceNode);
@@ -239,6 +83,10 @@
/// reader.readEdge("observed", edge);
/// \endcode
///
+ /// With the \c readAttribute() functions you can read an attribute
+ /// in a variable. You can specify the reader for the attribute as
+ /// the nodemaps.
+ ///
/// After you give all read commands you must call the \c run() member
/// function, which execute all the commands.
///
@@ -260,31 +108,56 @@
typedef typename Graph::Edge Edge;
typedef _ReaderTraits ReaderTraits;
- typedef typename ReaderTraits::DefaultReader DefaultReader;
+ typedef typename ReaderTraits::Skipper DefaultSkipper;
/// \brief Construct a new GraphReader.
///
/// Construct a new GraphReader. It reads into the given graph
/// and it use the given reader as the default skipper.
GraphReader(std::istream& _is, Graph& _graph,
- const DefaultReader& _reader = DefaultReader())
- : gui_reader(0), is(_is), graph(_graph),
- nodeSkipper(_reader), edgeSkipper(_reader) {}
+ const DefaultSkipper& _skipper = DefaultSkipper())
+ : reader(new LemonReader(_is)), own_reader(true),
+ graph(_graph), skipper(_skipper),
+ nodeset_reader(*reader, graph, std::string(), skipper),
+ edgeset_reader(*reader, graph, nodeset_reader, std::string(), skipper),
+ node_reader(*reader, nodeset_reader, std::string()),
+ edge_reader(*reader, edgeset_reader, std::string()),
+ attribute_reader(*reader, std::string()) {}
+
+ /// \brief Construct a new GraphReader.
+ ///
+ /// Construct a new GraphReader. It reads into the given graph
+ /// and it use the given reader as the default skipper.
+ GraphReader(const std::string& _filename, Graph& _graph,
+ const DefaultSkipper& _skipper = DefaultSkipper())
+ : reader(new LemonReader(_filename)), own_reader(true),
+ graph(_graph), skipper(_skipper),
+ nodeset_reader(*reader, graph, std::string(), skipper),
+ edgeset_reader(*reader, graph, nodeset_reader, std::string(), skipper),
+ node_reader(*reader, nodeset_reader, std::string()),
+ edge_reader(*reader, edgeset_reader, std::string()),
+ attribute_reader(*reader, std::string()) {}
+
+ /// \brief Construct a new GraphReader.
+ ///
+ /// Construct a new GraphReader. It reads into the given graph
+ /// and it use the given reader as the default skipper.
+ GraphReader(LemonReader& _reader, Graph& _graph,
+ const DefaultSkipper& _skipper = DefaultSkipper())
+ : reader(_reader), own_reader(false),
+ graph(_graph), skipper(_skipper),
+ nodeset_reader(*reader, graph, std::string(), skipper),
+ edgeset_reader(*reader, graph, nodeset_reader, std::string(), skipper),
+ node_reader(*reader, nodeset_reader, std::string()),
+ edge_reader(*reader, edgeset_reader, std::string()),
+ attribute_reader(*reader, std::string()) {}
/// \brief Destruct the graph reader.
///
/// Destruct the graph reader.
~GraphReader() {
- for (typename NodeMapReaders::iterator it = node_map_readers.begin();
- it != node_map_readers.end(); ++it) {
- delete it->second;
- }
-
- for (typename EdgeMapReaders::iterator it = edge_map_readers.begin();
- it != edge_map_readers.end(); ++it) {
- delete it->second;
- }
-
+ if (own_reader)
+ delete reader;
}
/// \brief Add a new node map reader command for the reader.
@@ -292,8 +165,8 @@
/// Add a new node map reader command for the reader.
template <typename Map>
GraphReader& readNodeMap(std::string name, Map& map) {
- return readNodeMap<typename ReaderTraits::template
- Reader<typename Map::Value>, Map>(name, map);
+ nodeset_reader.readMap(name, map);
+ return *this;
}
/// \brief Add a new node map reader command for the reader.
@@ -302,13 +175,7 @@
template <typename Reader, typename Map>
GraphReader& readNodeMap(std::string name, Map& map,
const Reader& reader = Reader()) {
- if (node_map_readers.find(name) != node_map_readers.end()) {
- ErrorMessage msg;
- msg << "Multiple read rule for node map: " << name;
- throw IOParameterError(msg.message());
- }
- node_map_readers.insert(
- make_pair(name, new MapReader<Node, Map, Reader>(map, reader)));
+ nodeset_reader.readMap(name, map, reader);
return *this;
}
@@ -318,13 +185,7 @@
template <typename Reader>
GraphReader& skipNodeMap(std::string name,
const Reader& reader = Reader()) {
- if (node_map_readers.find(name) != node_map_readers.end()) {
- ErrorMessage msg;
- msg << "Multiple read rule for node map: " << name;
- throw IOParameterError(msg.message());
- }
- node_map_readers.insert(
- make_pair(name, new SkipReader<Node, Reader>(reader)));
+ nodeset_reader.skipMap(name, reader);
return *this;
}
@@ -333,8 +194,8 @@
/// Add a new edge map reader command for the reader.
template <typename Map>
GraphReader& readEdgeMap(std::string name, Map& map) {
- return readEdgeMap<typename ReaderTraits::template
- Reader<typename Map::Value>, Map>(name, map);
+ edgeset_reader.readMap(name, map);
+ return *this;
}
@@ -344,13 +205,7 @@
template <typename Reader, typename Map>
GraphReader& readEdgeMap(std::string name, Map& map,
const Reader& reader = Reader()) {
- if (edge_map_readers.find(name) != edge_map_readers.end()) {
- ErrorMessage msg;
- msg << "Multiple read rule for edge map: " << name;
- throw IOParameterError(msg.message());
- }
- edge_map_readers.insert(
- make_pair(name, new MapReader<Edge, Map, Reader>(map, reader)));
+ edgeset_reader.readMap(name, map, reader);
return *this;
}
@@ -360,13 +215,8 @@
template <typename Reader>
GraphReader& skipEdgeMap(std::string name,
const Reader& reader = Reader()) {
- if (edge_map_readers.find(name) != edge_map_readers.end()) {
- ErrorMessage msg;
- msg << "Multiple read rule for edge map: " << name;
- throw IOParameterError(msg.message());
- }
- edge_map_readers.insert(
- make_pair(name, new SkipReader<Edge, Reader>(reader)));
+
+ edgeset_reader.skipMap(name, reader);
return *this;
}
@@ -374,12 +224,7 @@
///
/// Add a new labeled node reader for the reader.
GraphReader& readNode(std::string name, Node& node) {
- if (node_readers.find(name) != node_readers.end()) {
- ErrorMessage msg;
- msg << "Multiple read rule for node: " << name;
- throw IOParameterError(msg.message());
- }
- node_readers.insert(make_pair(name, &node));
+ node_reader.readNode(name, node);
return *this;
}
@@ -387,385 +232,61 @@
///
/// Add a new labeled edge reader for the reader.
GraphReader& readEdge(std::string name, Edge& edge) {
- if (edge_readers.find(name) != edge_readers.end()) {
- ErrorMessage msg;
- msg << "Multiple read rule for edge: " << name;
- throw IOParameterError(msg.message());
- }
- edge_readers.insert(make_pair(name, &edge));
- return *this;
+ edge_reader.readEdge(name, edge);
}
- /// \brief Executes the reader commands.
+ /// \brief Add a new attribute reader command.
///
- /// Executes the reader commands.
- void run() {
- int line_num = 0;
- std::auto_ptr<InverterBase<Node> > nodeInverter;
- std::auto_ptr<InverterBase<Edge> > edgeInverter;
- try {
- std::string line = readNotEmptyLine(is, line_num);
- if (line.find("@nodeset") == 0) {
- line = readNodeSet(line_num, nodeInverter);
- }
- if (line.find("@edgeset") == 0) {
- line = readEdgeSet(line_num, edgeInverter, nodeInverter);
- }
- if (line.find("@nodes") == 0) {
- line = readNodes(line_num, nodeInverter);
- }
- if (line.find("@edges") == 0) {
- line = readEdges(line_num, edgeInverter);
- }
- if (line.find("@gui") == 0) {
- line = readGUI(line_num);
- }
- if (line.find("@end") != 0) {
- throw DataFormatError("Invalid control sequence error");
- }
- } catch (DataFormatError e) {
- e.line(line_num);
- throw e;
- }
+ /// Add a new attribute reader command.
+ template <typename Value>
+ GraphReader& readAttribute(std::string name, Value& value) {
+ attribute_reader.readAttribute(name, value);
+ return *this;
}
-
- GraphReader& readGUI(GUIReader& reader) {
- gui_reader = &reader;
+
+ /// \brief Add a new attribute reader command.
+ ///
+ /// Add a new attribute reader command.
+ template <typename Reader, typename Value>
+ GraphReader& readAttribute(std::string name, Value& value,
+ const Reader& reader) {
+ attribute_reader.readAttribute<Reader>(name, value, reader);
return *this;
}
- private:
-
- template <typename Item> class InverterBase;
+ /// \brief Conversion operator to LemonReader.
+ ///
+ /// Conversion operator to LemonReader. It make possible
+ /// to access the encapsulated \e LemonReader, this way
+ /// you can attach to this reader new instances of
+ /// \e LemonReader::SectionReader.
+ operator LemonReader&() {
+ return *reader;
+ }
- std::string readNodeSet(int& line_num,
- std::auto_ptr<InverterBase<Node> >& nodeInverter) {
- std::vector<ReaderBase<Node>* > index;
- {
- std::string line = readNotEmptyLine(is, line_num);
- std::string id;
- std::istringstream ls(line);
- while (ls >> id) {
- typename NodeMapReaders::iterator it = node_map_readers.find(id);
- if (it != node_map_readers.end()) {
- index.push_back(it->second);
- node_map_readers.erase(it);
- } else {
- index.push_back(&nodeSkipper);
- }
- if (ReaderTraits::idMapName(id) && nodeInverter.get() == 0) {
- nodeInverter.reset(index.back()->getInverter());
- index.back() = nodeInverter.get();
- }
- }
- }
-
-// if (index.size() == 0) {
-// throw DataFormatError("Cannot find node id map");
-// }
-
-// nodeInverter =
-// std::auto_ptr<InverterBase<Node> >(index[0]->getInverter());
- std::string line;
- while (line = readNotEmptyLine(is, line_num), line[0] != '@') {
- Node node = graph.addNode();
- std::istringstream ls(line);
- for (int i = 0; i < (int)index.size(); ++i) {
- index[i]->read(ls, node);
- }
- }
- return line;
- }
-
- std::string readEdgeSet(int& line_num,
- std::auto_ptr<InverterBase<Edge> >& edgeInverter,
- std::auto_ptr<InverterBase<Node> >& nodeInverter) {
- std::vector<ReaderBase<Edge>*> index;
- {
- std::string line = readNotEmptyLine(is, line_num);
- std::string id;
- std::istringstream ls(line);
- while (ls >> id) {
- typename EdgeMapReaders::iterator it = edge_map_readers.find(id);
- if (it != edge_map_readers.end()) {
- index.push_back(it->second);
- edge_map_readers.erase(it);
- } else {
- index.push_back(&edgeSkipper);
- }
- if (ReaderTraits::idMapName(id) && edgeInverter.get() == 0) {
- edgeInverter.reset(index.back()->getInverter());
- index.back() = edgeInverter.get();
- }
- }
- }
-
- if (nodeInverter.get() == 0) {
- throw DataFormatError("Cannot find node id map");
- }
-// if (index.size() == 0) {
-// throw DataFormatError("Cannot find edge id map");
-// }
-
-// edgeInverter =
-// std::auto_ptr<InverterBase<Edge> >(index[0]->getInverter());
- std::string line;
- while (line = readNotEmptyLine(is, line_num), line[0] != '@') {
- std::istringstream ls(line);
- Node source = nodeInverter->read(ls);
- Node target = nodeInverter->read(ls);
- Edge edge = graph.addEdge(source, target);
- for (int i = 0; i < (int)index.size(); ++i) {
- index[i]->read(ls, edge);
- }
- }
- return line;
- }
-
- std::string readNodes(int& line_num,
- std::auto_ptr<InverterBase<Node> >& nodeInverter) {
- std::string line;
- if (nodeInverter.get() == 0) {
- throw DataFormatError("Cannot find node id map");
- }
- while (line = readNotEmptyLine(is, line_num), line[0] != '@') {
- std::istringstream ls(line);
- std::string name;
- ls >> name;
- typename NodeReaders::iterator it = node_readers.find(name);
- if (it != node_readers.end()) {
- *(it -> second) = nodeInverter->read(ls);
- }
- }
- return line;
- }
-
- std::string readEdges(int& line_num,
- std::auto_ptr<InverterBase<Edge> >& edgeInverter) {
- std::string line;
- if (edgeInverter.get() == 0) {
- throw DataFormatError("Cannot find edge id map");
- }
- while (line = readNotEmptyLine(is, line_num), line[0] != '@') {
- std::istringstream ls(line);
- std::string name;
- ls >> name;
- typename EdgeReaders::iterator it = edge_readers.find(name);
- if (it != edge_readers.end()) {
- *(it -> second) = edgeInverter->read(ls);
- }
- }
- return line;
- }
-
- std::string readGUI(int& line_num) {
- std::stringstream section;
- std::string line;
- while (line = readNotEmptyLine(is, line_num), line[0] != '@') {
- section << line << std::endl;
- }
- if (gui_reader != 0) {
- gui_reader->read(section);
- }
- return line;
- }
-
- std::string readNotEmptyLine(std::istream& is, int& line_num) {
- std::string line;
- while (++line_num, getline(is, line)) {
- int vi = line.find('#');
- if (vi != (int)::std::string::npos) {
- line = line.substr(0, vi);
- }
- vi = line.find_first_not_of(" \t");
- if (vi != (int)std::string::npos) {
- return line.substr(vi);
- }
- }
- throw DataFormatError("End of stream error");
+ /// \brief Executes the reader commands.
+ ///
+ /// Executes the reader commands.
+ void run() {
+ reader->run();
}
-
- template <typename _Item>
- class ReaderBase;
-
- template <typename _Item>
- class InverterBase : public ReaderBase<_Item> {
- public:
- typedef _Item Item;
- virtual void read(std::istream&, const Item&) = 0;
- virtual Item read(std::istream&) = 0;
-
- virtual InverterBase<_Item>* getInverter() {
- return this;
- }
- };
-
- template <typename _Item, typename _Map, typename _Reader>
- class MapReaderInverter : public InverterBase<_Item> {
- public:
- typedef _Item Item;
- typedef _Reader Reader;
- typedef typename Reader::Value Value;
- typedef _Map Map;
- typedef std::map<Value, Item> Inverse;
-
- Map& map;
- Reader reader;
- Inverse inverse;
-
- MapReaderInverter(Map& _map, const Reader& _reader)
- : map(_map), reader(_reader) {}
-
- virtual ~MapReaderInverter() {}
-
- virtual void read(std::istream& is, const Item& item) {
- Value value;
- reader.read(is, value);
- map.set(item, value);
- typename Inverse::iterator it = inverse.find(value);
- if (it == inverse.end()) {
- inverse.insert(std::make_pair(value, item));
- } else {
- throw DataFormatError("Multiple ID occurence");
- }
- }
-
- virtual Item read(std::istream& is) {
- Value value;
- reader.read(is, value);
- typename Inverse::const_iterator it = inverse.find(value);
- if (it != inverse.end()) {
- return it->second;
- } else {
- throw DataFormatError("Invalid ID error");
- }
- }
- };
-
- template <typename _Item, typename _Reader>
- class SkipReaderInverter : public InverterBase<_Item> {
- public:
- typedef _Item Item;
- typedef _Reader Reader;
- typedef typename Reader::Value Value;
- typedef std::map<Value, Item> Inverse;
-
- Reader reader;
-
- SkipReaderInverter(const Reader& _reader)
- : reader(_reader) {}
-
- virtual ~SkipReaderInverter() {}
-
- virtual void read(std::istream& is, const Item& item) {
- Value value;
- reader.read(is, value);
- typename Inverse::iterator it = inverse.find(value);
- if (it == inverse.end()) {
- inverse.insert(std::make_pair(value, item));
- } else {
- throw DataFormatError("Multiple ID occurence error");
- }
- }
-
- virtual Item read(std::istream& is) {
- Value value;
- reader.read(is, value);
- typename Inverse::const_iterator it = inverse.find(value);
- if (it != inverse.end()) {
- return it->second;
- } else {
- throw DataFormatError("Invalid ID error");
- }
- }
- private:
- Inverse inverse;
- };
-
- // Readers
-
- template <typename _Item>
- class ReaderBase {
- public:
- typedef _Item Item;
-
- // virtual ~ReaderBase() {}
-
- virtual void read(std::istream& is, const Item& item) = 0;
- virtual InverterBase<_Item>* getInverter() = 0;
- };
-
- template <typename _Item, typename _Map, typename _Reader>
- class MapReader : public ReaderBase<_Item> {
- public:
- typedef _Map Map;
- typedef _Reader Reader;
- typedef typename Reader::Value Value;
- typedef _Item Item;
-
- Map& map;
- Reader reader;
-
- MapReader(Map& _map, const Reader& _reader)
- : map(_map), reader(_reader) {}
-
- virtual ~MapReader() {}
-
- virtual void read(std::istream& is, const Item& item) {
- Value value;
- reader.read(is, value);
- map.set(item, value);
- }
-
- virtual InverterBase<_Item>* getInverter() {
- return new MapReaderInverter<Item, Map, Reader>(map, reader);
- }
- };
-
-
- template <typename _Item, typename _Reader>
- class SkipReader : public ReaderBase<_Item> {
- public:
- typedef _Reader Reader;
- typedef typename Reader::Value Value;
- typedef _Item Item;
-
- Reader reader;
- SkipReader(const Reader& _reader) : reader(_reader) {}
-
- virtual ~SkipReader() {}
-
- virtual void read(std::istream& is, const Item&) {
- Value value;
- reader.read(is, value);
- }
-
- virtual InverterBase<Item>* getInverter() {
- return new SkipReaderInverter<Item, Reader>(reader);
- }
- };
-
-
- typedef std::map<std::string, ReaderBase<Node>*> NodeMapReaders;
- NodeMapReaders node_map_readers;
-
- typedef std::map<std::string, ReaderBase<Edge>*> EdgeMapReaders;
- EdgeMapReaders edge_map_readers;
-
- typedef std::map<std::string, Node*> NodeReaders;
- NodeReaders node_readers;
- typedef std::map<std::string, Edge*> EdgeReaders;
- EdgeReaders edge_readers;
+ private:
- GUIReader* gui_reader;
+ LemonReader* reader;
+ bool own_reader;
- std::istream& is;
Graph& graph;
- SkipReader<Node, DefaultReader> nodeSkipper;
- SkipReader<Edge, DefaultReader> edgeSkipper;
+ DefaultSkipper skipper;
+ NodeSetReader<Graph, ReaderTraits> nodeset_reader;
+ EdgeSetReader<Graph, ReaderTraits> edgeset_reader;
+
+ NodeReader<Graph> node_reader;
+ EdgeReader<Graph> edge_reader;
+
+ AttributeReader<ReaderTraits> attribute_reader;
};
/// \brief Read a graph from the input.
Copied: hugo/trunk/src/lemon/lemon_reader.h (from r1862, /hugo_loc/work/deba/lemon_reader.h)
==============================================================================
--- /hugo_loc/work/deba/lemon_reader.h (original)
+++ hugo/trunk/src/lemon/lemon_reader.h Mon May 9 13:24:26 2005
@@ -30,16 +30,41 @@
#include <memory>
#include <lemon/error.h>
-#include "item_reader.h"
+#include <lemon/bits/item_reader.h>
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 an 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,54 @@
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 Header checking function.
+ ///
+ /// 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 Reading function.
+ ///
+ /// It processes 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 +268,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<SectionReader*>::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 +310,20 @@
};
-
- /// \e
+ /// \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) {}
+
template <typename _Item>
class ReaderBase;
@@ -479,7 +535,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 resolve() member will read a value from the given stream it will
+ /// give back that node which is mapped to the value.
+ ///
+ /// \relates LemonReader
template <typename _Graph, typename _Traits = DefaultReaderTraits>
class NodeSetReader : public CommonSectionReaderBase {
typedef CommonSectionReaderBase Parent;
@@ -490,13 +562,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
+ /// be add the readed nodes to the given Graph. The reader will read
+ /// the section when the \c section_id and the _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 +630,12 @@
return *this;
}
- /// \e
+ protected:
+
+ /// \brief Header checking function.
+ ///
+ /// It gives back true when the header line start 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 +644,9 @@
return command == "@nodeset" && name == id;
}
- /// \e
+ /// \brief Reading function.
+ ///
+ /// It processes the section.
virtual void read(std::istream& is) {
std::vector<ReaderBase<Item>* > index;
std::string line;
@@ -587,10 +674,20 @@
}
}
+ public:
+
+ /// \brief Decide if it can resolve nodes by ids.
+ ///
+ /// Decide if it can resolve nodes by ids. It depends on that the
+ /// readed file contains \c "id" named map.
bool isResolver() const {
return inverter.get() != 0;
}
+ /// \brief Node resolver function.
+ ///
+ /// It reads from the given stream an id and gives back
+ /// the node that the id belongs to.
typename Graph::Node resolve(std::istream& is) const {
return inverter->read(is);
}
@@ -607,9 +704,27 @@
std::auto_ptr<InverterBase<Item> > 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 resolve() member will read a value from the given stream it will
+ /// give back that node which is mapped to the value.
+ ///
+ /// The edgeset reader needs a node resolver 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 <typename _Graph, typename _Traits = DefaultReaderTraits>
class EdgeSetReader : public CommonSectionReaderBase {
typedef CommonSectionReaderBase Parent;
@@ -620,17 +735,25 @@
typedef typename Graph::Edge Item;
typedef typename Traits::Skipper DefaultSkipper;
+ /// \brief Constructor.
+ ///
+ /// Constructor for EdgeSetReader. It creates the EdgeSetReader and
+ /// attach it into the given LemonReader. The edgeset reader will
+ /// be add the readed edges to the given Graph. It will resolve the nodes
+ /// by id with the given Resolver. The reader will read the section
+ /// only if the \c _id and the \c edgset_id are the same.
template <typename Resolver>
EdgeSetReader(LemonReader& _reader, Graph& _graph,
const Resolver& _nodeResolver,
const std::string& _id = std::string(),
const DefaultSkipper& _defreader = DefaultSkipper())
- : graph(_graph), id(_id), skipper(_defreader),
- nodeResolver(new ResolverReader<typename Graph::Node, Resolver>
- (_nodeResolver)) {
- _reader.attach(*this);
- }
+ : Parent(_reader), graph(_graph), id(_id), skipper(_defreader),
+ nodeResolver(new ResolverReader<typename Graph::Node, Resolver>
+ (_nodeResolver)) {}
+ /// \brief Destructor.
+ ///
+ /// Destructor for EdgeSetReader.
virtual ~EdgeSetReader() {
for (typename MapReaders::iterator it = readers.begin();
it != readers.end(); ++it) {
@@ -684,7 +807,12 @@
return *this;
}
- /// \e
+ protected:
+
+ /// \brief Header checking function.
+ ///
+ /// It gives back true when the header line start 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 +821,9 @@
return command == "@edgeset" && name == id;
}
- /// \e
+ /// \brief Reading function.
+ ///
+ /// It processes the section.
virtual void read(std::istream& is) {
std::vector<ReaderBase<Item>* > index;
std::string line;
@@ -723,11 +853,21 @@
}
}
+ public:
+
+ /// \brief Decide if it can resolve edges by ids.
+ ///
+ /// Decide if it can resolve edges by ids. It depends on that the
+ /// readed file contains \c "id" named map.
bool isResolver() const {
return inverter.get() != 0;
}
- typename Graph::Edge resolve(std::istream& is) {
+ /// \brief Edge resolver function.
+ ///
+ /// It reads from the given stream an id and gives back
+ /// the edge that the id belongs to.
+ typename Graph::Edge resolve(std::istream& is) const {
return inverter->read(is);
}
@@ -744,84 +884,15 @@
std::auto_ptr<ResolverReaderBase<typename Graph::Node> > nodeResolver;
};
-
- /// \e
- template <typename _Traits = DefaultReaderTraits>
- class AttributeReader : public CommonSectionReaderBase {
- typedef CommonSectionReaderBase Parent;
- typedef _Traits Traits;
- public:
- /// \e
- AttributeReader(LemonReader& _reader,
- const std::string& _id = std::string()) : id(_id) {
- _reader.attach(*this);
- }
-
- /// \e
- virtual ~AttributeReader() {
- for (typename Readers::iterator it = readers.begin();
- it != readers.end(); ++it) {
- delete it->second;
- }
- }
-
- private:
- AttributeReader(const AttributeReader&);
- void operator=(AttributeReader&);
-
- public:
- /// \e
- template <typename Value>
- AttributeReader& readAttribute(const std::string& id, Value& value) {
- return readAttribute<typename Traits::template Reader<Value> >
- (id, value);
- }
-
- /// \e
- template <typename Reader, typename Value>
- AttributeReader& readAttribute(const std::string& name, Value& value,
- const Reader& reader = Reader()) {
- if (readers.find(name) != readers.end()) {
- ErrorMessage msg;
- msg << "Multiple read rule for attribute: " << name;
- throw IOParameterError(msg.message());
- }
- readers.insert(make_pair(name, new ValueReader<Value, Reader>
- (value, reader)));
- return *this;
- }
-
- /// \e
- bool header(const std::string& line) {
- std::istringstream ls(line);
- std::string command;
- std::string name;
- ls >> command >> name;
- return command == "@attributes" && name == id;
- }
-
- /// \e
- void read(std::istream& is) {
- std::string line;
- while (getline(is, line)) {
- std::istringstream ls(line);
- std::string id;
- ls >> id;
- typename Readers::iterator it = readers.find(id);
- if (it != readers.end()) {
- it->second->read(ls);
- }
- }
- }
-
- private:
- std::string id;
-
- typedef std::map<std::string, ValueReaderBase*> Readers;
- Readers readers;
-
- };
-
+ /// \ingroup io_group
+ /// \brief SectionReader for reading labelled 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 a name and then a node id.
+ ///
+ /// \relates LemonReader
template <typename _Graph>
class NodeReader : public CommonSectionReaderBase {
typedef CommonSectionReaderBase Parent;
@@ -829,14 +900,22 @@
typedef typename Graph::Node Item;
public:
+ /// \brief Constructor.
+ ///
+ /// Constructor for NodeReader. It creates the NodeReader and
+ /// attach it into the given LemonReader. It will resolve the nodes
+ /// by id with the given Resolver. The reader will read the section
+ /// only if the \c _id and the \c nodes_id are the same.
template <typename Resolver>
NodeReader(LemonReader& _reader, const Resolver& _resolver,
const std::string& _id = std::string())
- : id(_id), resolver(new ResolverReader<typename Graph::Node, Resolver>
- (_resolver)) {
- _reader.attach(*this);
- }
+ : Parent(_reader), id(_id),
+ resolver(new ResolverReader<typename Graph::Node, Resolver>
+ (_resolver)) {}
+ /// \brief Destructor.
+ ///
+ /// Destructor for NodeReader.
virtual ~NodeReader() {}
private:
@@ -845,6 +924,9 @@
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;
@@ -854,6 +936,12 @@
readers.insert(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 reader's id are the same.
virtual bool header(const std::string& line) {
std::istringstream ls(line);
std::string command;
@@ -862,6 +950,9 @@
return command == "@nodes" && name == id;
}
+ /// \brief Reading function.
+ ///
+ /// It processes the section.
virtual void read(std::istream& is) {
std::string line;
while (getline(is, line)) {
@@ -884,6 +975,15 @@
std::auto_ptr<ResolverReaderBase<Item> > resolver;
};
+ /// \ingroup io_group
+ /// \brief SectionReader for reading labelled 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 a name and then a edge id.
+ ///
+ /// \relates LemonReader
template <typename _Graph>
class EdgeReader : public CommonSectionReaderBase {
typedef CommonSectionReaderBase Parent;
@@ -891,14 +991,22 @@
typedef typename Graph::Edge Item;
public:
+ /// \brief Constructor.
+ ///
+ /// Constructor for EdgeReader. It creates the EdgeReader and
+ /// attach it into the given LemonReader. It will resolve the edges
+ /// by id with the given Resolver. The reader will read the section
+ /// only if the \c _id and the \c edges_id are the same.
template <typename Resolver>
EdgeReader(LemonReader& _reader, const Resolver& _resolver,
const std::string& _id = std::string())
- : id(_id), resolver(new ResolverReader<typename Graph::Node, Resolver>
- (_resolver)) {
- _reader.attach(*this);
- }
+ : Parent(_reader), id(_id),
+ resolver(new ResolverReader<typename Graph::Edge, Resolver>
+ (_resolver)) {}
+ /// \brief Destructor.
+ ///
+ /// Destructor for EdgeReader.
virtual ~EdgeReader() {}
private:
EdgeReader(const EdgeReader&);
@@ -906,6 +1014,9 @@
public:
+ /// \brief Add an edge reader command for the NodeReader.
+ ///
+ /// Add an edge reader command for the NodeReader.
void readEdge(const std::string& name, Item& item) {
if (readers.find(name) != readers.end()) {
ErrorMessage msg;
@@ -915,15 +1026,23 @@
readers.insert(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 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;
+ return command == "@edges" && name == id;
}
+ /// \brief Reading function.
+ ///
+ /// It processes the section.
virtual void read(std::istream& is) {
std::string line;
while (getline(is, line)) {
@@ -946,32 +1065,108 @@
std::auto_ptr<ResolverReaderBase<Item> > resolver;
};
- /// \e
- class PrintReader : public LemonReader::SectionReader {
- typedef LemonReader::SectionReader Parent;
+ /// \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 is and then a the value for the id.
+ ///
+ /// \relates LemonReader
+ template <typename _Traits = DefaultReaderTraits>
+ class AttributeReader : public CommonSectionReaderBase {
+ typedef CommonSectionReaderBase Parent;
+ typedef _Traits Traits;
+ public:
+ /// \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())
+ : Parent(_reader), id(_id) {}
+
+ /// \brief Destructor.
+ ///
+ /// Destructor for AttributeReader.
+ virtual ~AttributeReader() {
+ for (typename Readers::iterator it = readers.begin();
+ it != readers.end(); ++it) {
+ delete it->second;
+ }
+ }
+
+ private:
+ AttributeReader(const AttributeReader&);
+ void operator=(AttributeReader&);
+
public:
+ /// \brief Add an attribute reader command for the reader.
+ ///
+ /// Add an attribute reader command for the reader.
+ template <typename Value>
+ AttributeReader& readAttribute(const std::string& id, Value& value) {
+ return readAttribute<typename Traits::template Reader<Value> >
+ (id, value);
+ }
- /// \e
- PrintReader(LemonReader& reader) {
- reader.attach(*this);
+ /// \brief Add an attribute reader command for the reader.
+ ///
+ /// Add an attribute reader command for the reader.
+ template <typename Reader, typename Value>
+ AttributeReader& readAttribute(const std::string& name, Value& value,
+ const Reader& reader = Reader()) {
+ if (readers.find(name) != readers.end()) {
+ ErrorMessage msg;
+ msg << "Multiple read rule for attribute: " << name;
+ throw IOParameterError(msg.message());
+ }
+ readers.insert(make_pair(name, new ValueReader<Value, Reader>
+ (value, reader)));
+ return *this;
}
- /// \e
+ protected:
+
+ /// \brief Header checking function.
+ ///
+ /// 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::cout << "Asked header: " << line << std::endl;
- return true;
+ std::istringstream ls(line);
+ std::string command;
+ std::string name;
+ ls >> command >> name;
+ return command == "@attributes" && name == id;
}
- /// \e
+ /// \brief Reading function.
+ ///
+ /// It processes the section.
void read(std::istream& is) {
std::string line;
- while (std::getline(is, line)) {
- std::cout << line << std::endl;
+ while (getline(is, line)) {
+ std::istringstream ls(line);
+ std::string id;
+ ls >> id;
+ typename Readers::iterator it = readers.find(id);
+ if (it != readers.end()) {
+ it->second->read(ls);
+ }
}
- }
-
+ }
+
+ private:
+ std::string id;
+
+ typedef std::map<std::string, ValueReaderBase*> Readers;
+ Readers readers;
};
- /// @}
+
}
#endif
More information about the Lemon-commits
mailing list