[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