[Lemon-commits] [lemon_svn] deba: r1891 - hugo/trunk/src/lemon

Lemon SVN svn at lemon.cs.elte.hu
Mon Nov 6 20:48:30 CET 2006


Author: deba
Date: Sat May 14 19:39:37 2005
New Revision: 1891

Modified:
   hugo/trunk/src/lemon/graph_reader.h
   hugo/trunk/src/lemon/graph_writer.h
   hugo/trunk/src/lemon/lemon_reader.h
   hugo/trunk/src/lemon/lemon_writer.h

Log:
IO with undirected edgesets and undirected graphs.
Missing features:
    InfoReader,
    aliased edges in undir edgesets
    



Modified: hugo/trunk/src/lemon/graph_reader.h
==============================================================================
--- hugo/trunk/src/lemon/graph_reader.h	(original)
+++ hugo/trunk/src/lemon/graph_reader.h	Sat May 14 19:39:37 2005
@@ -56,8 +56,7 @@
   /// parameters.
   ///
   /// \code
-  /// reader.readNodeMap("x-coord", xCoordMap);
-  /// reader.readNodeMap("y-coord", yCoordMap);
+  /// reader.readNodeMap("coords", coords);
   ///
   /// reader.readNodeMap<QuotedStringReader>("label", labelMap);
   /// reader.skipNodeMap<QuotedStringReader>("description");
@@ -114,12 +113,13 @@
     ///
     /// 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, 
+    GraphReader(std::istream& _is, 
+		typename SmartParameter<Graph>::Type _graph, 
 		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),
+      : reader(new LemonReader(_is)), own_reader(true), 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()) {}
@@ -128,12 +128,14 @@
     ///
     /// 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, 
+    GraphReader(const std::string& _filename, 
+		typename SmartParameter<Graph>::Type _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),
+	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()) {}
@@ -142,12 +144,13 @@
     ///
     /// 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, 
+    GraphReader(LemonReader& _reader, 
+		typename SmartParameter<Graph>::Type _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),
+      : reader(_reader), own_reader(false), 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()) {}
@@ -165,7 +168,13 @@
     /// Add a new node map reader command for the reader.
     template <typename Map>
     GraphReader& readNodeMap(std::string name, Map& map) {
-      nodeset_reader.readMap(name, map);
+      nodeset_reader.readNodeMap(name, map);
+      return *this;
+    }
+
+    template <typename Map>
+    GraphReader& readNodeMap(std::string name, const Map& map) {
+      nodeset_reader.readNodeMap(name, map);
       return *this;
     }
 
@@ -175,7 +184,14 @@
     template <typename Reader, typename Map>
     GraphReader& readNodeMap(std::string name, Map& map, 
 			     const Reader& reader = Reader()) {
-      nodeset_reader.readMap(name, map, reader);
+      nodeset_reader.readNodeMap(name, map, reader);
+      return *this;
+    }
+
+    template <typename Reader, typename Map>
+    GraphReader& readNodeMap(std::string name, const Map& map, 
+			     const Reader& reader = Reader()) {
+      nodeset_reader.readNodeMap(name, map, reader);
       return *this;
     }
 
@@ -185,7 +201,7 @@
     template <typename Reader>
     GraphReader& skipNodeMap(std::string name, 
 			     const Reader& reader = Reader()) {
-      nodeset_reader.skipMap(name, reader);
+      nodeset_reader.skipNodeMap(name, reader);
       return *this;
     }
 
@@ -194,7 +210,13 @@
     /// Add a new edge map reader command for the reader.
     template <typename Map>
     GraphReader& readEdgeMap(std::string name, Map& map) { 
-      edgeset_reader.readMap(name, map);
+      edgeset_reader.readEdgeMap(name, map);
+      return *this;
+    }
+
+    template <typename Map>
+    GraphReader& readEdgeMap(std::string name, const Map& map) { 
+      edgeset_reader.readEdgeMap(name, map);
       return *this;
     }
 
@@ -205,7 +227,14 @@
     template <typename Reader, typename Map>
     GraphReader& readEdgeMap(std::string name, Map& map,
 			     const Reader& reader = Reader()) {
-      edgeset_reader.readMap(name, map, reader);
+      edgeset_reader.readEdgeMap(name, map, reader);
+      return *this;
+    }
+
+    template <typename Reader, typename Map>
+    GraphReader& readEdgeMap(std::string name, const Map& map,
+			     const Reader& reader = Reader()) {
+      edgeset_reader.readEdgeMap(name, map, reader);
       return *this;
     }
 
@@ -213,10 +242,9 @@
     ///
     /// Add a new edge map skipper command for the reader.
     template <typename Reader>
-    GraphReader& skipEdgeMap(std::string name,
+    GraphReader& skipEdgeMap(std::string name, 
 			     const Reader& reader = Reader()) {
-
-      edgeset_reader.skipMap(name, reader);
+      edgeset_reader.skipEdgeMap(name, reader);
       return *this;
     }
 
@@ -276,8 +304,6 @@
     LemonReader* reader;
     bool own_reader;
 
-    Graph& graph;
-
     DefaultSkipper skipper;
 
     NodeSetReader<Graph, ReaderTraits> nodeset_reader;
@@ -368,6 +394,365 @@
     reader.run();
   }
 
+  /// \brief The undir graph reader class.
+  ///
+  /// The given file format may contain several maps and labeled nodes or 
+  /// edges.
+  ///
+  /// If you read a graph you need not read all the maps and items just those
+  /// that you need. The interface of the \c GraphReader is very similar to
+  /// the GraphWriter but the reading method does not depend on the order the
+  /// given commands.
+  ///
+  /// The reader object suppose that each not readed value does not contain 
+  /// whitespaces, therefore it has some extra possibilities to control how
+  /// it should skip the values when the string representation contains spaces.
+  ///
+  /// \code
+  /// UndirGraphReader<UndirListGraph> reader(std::cin, graph);
+  /// \endcode
+  ///
+  /// The \c readNodeMap() function reads a map from the \c \@nodeset section.
+  /// If there is a map that you do not want to read from the file and there is
+  /// whitespace in the string represenation of the values then you should
+  /// call the \c skipNodeMap() template member function with proper 
+  /// parameters.
+  ///
+  /// \code
+  /// reader.readNodeMap("coords", coords);
+  ///
+  /// reader.readNodeMap<QuotedStringReader>("label", labelMap);
+  /// reader.skipNodeMap<QuotedStringReader>("description");
+  ///
+  /// reader.readNodeMap("color", colorMap);
+  /// \endcode
+  ///
+  /// With the \c readUndirEdgeMap() member function you can give an 
+  /// undir edge map reading command similar to the NodeMaps. 
+  ///
+  /// \code
+  /// reader.readUndirEdgeMap("capacity", capacityMap);
+  /// \endcode
+  ///
+  /// The reading of the directed edge maps is just a syntactical sugar.
+  /// It reads two undirected edgemaps into a directed edge map. The 
+  /// undirected edge maps' name should be start with the \c '+' and the
+  /// \c '-' character and the same.
+  ///
+  /// \code
+  /// reader.readEdgeMap("flow", flowMap);
+  /// \endcode 
+  ///
+  /// With \c readNode() and \c readUndirEdge() functions you can read 
+  /// labeled Nodes and UndirEdges.
+  ///
+  /// \code
+  /// reader.readNode("source", sourceNode);
+  /// reader.readNode("target", targetNode);
+  ///
+  /// reader.readUndirEdge("observed", undirEdge);
+  /// \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.
+  ///
+  /// \code
+  /// reader.run();
+  /// \endcode
+  ///
+  /// \see GraphReader
+  /// \see DefaultReaderTraits
+  /// \see \ref UndirGraphWriter
+  /// \see \ref graph-io-page
+  ///
+  /// \author Balazs Dezso
+  template <typename _Graph, typename _ReaderTraits = DefaultReaderTraits> 
+  class UndirGraphReader {
+  public:
+    
+    typedef _Graph Graph;
+    typedef typename Graph::Node Node;
+    typedef typename Graph::Edge Edge;
+    typedef typename Graph::UndirEdge UndirEdge;
+
+    typedef _ReaderTraits ReaderTraits;
+    typedef typename ReaderTraits::Skipper DefaultSkipper;
+
+    /// \brief Construct a new UndirGraphReader.
+    ///
+    /// Construct a new UndirGraphReader. It reads into the given graph
+    /// and it use the given reader as the default skipper.
+    UndirGraphReader(std::istream& _is, Graph& _graph, 
+		     const DefaultSkipper& _skipper = DefaultSkipper()) 
+      : reader(new LemonReader(_is)), own_reader(true), skipper(_skipper),
+	nodeset_reader(*reader, _graph, std::string(), skipper),
+	undir_edgeset_reader(*reader, _graph, nodeset_reader, 
+			     std::string(), skipper),
+	node_reader(*reader, nodeset_reader, std::string()),
+	undir_edge_reader(*reader, undir_edgeset_reader, std::string()),
+	attribute_reader(*reader, std::string()) {}
+
+    /// \brief Construct a new UndirGraphReader.
+    ///
+    /// Construct a new UndirGraphReader. It reads into the given graph
+    /// and it use the given reader as the default skipper.
+    UndirGraphReader(const std::string& _filename, Graph& _graph, 
+		     const DefaultSkipper& _skipper = DefaultSkipper()) 
+      : reader(new LemonReader(_filename)), own_reader(true), 
+	skipper(_skipper),
+	nodeset_reader(*reader, _graph, std::string(), skipper),
+	undir_edgeset_reader(*reader, _graph, nodeset_reader, 
+			     std::string(), skipper),
+	node_reader(*reader, nodeset_reader, std::string()),
+	undir_edge_reader(*reader, undir_edgeset_reader, std::string()),
+	attribute_reader(*reader, std::string()) {}
+
+    /// \brief Construct a new UndirGraphReader.
+    ///
+    /// Construct a new UndirGraphReader. It reads into the given graph
+    /// and it use the given reader as the default skipper.
+    UndirGraphReader(LemonReader& _reader, Graph& _graph, 
+		     const DefaultSkipper& _skipper = DefaultSkipper()) 
+      : reader(_reader), own_reader(false), skipper(_skipper),
+	nodeset_reader(*reader, _graph, std::string(), skipper),
+	undir_edgeset_reader(*reader, _graph, nodeset_reader, 
+			     std::string(), skipper),
+	node_reader(*reader, nodeset_reader, std::string()),
+	undir_edge_reader(*reader, undir_edgeset_reader, std::string()),
+	attribute_reader(*reader, std::string()) {}
+
+    /// \brief Destruct the graph reader.
+    ///
+    /// Destruct the graph reader.
+    ~UndirGraphReader() {
+      if (own_reader) 
+	delete reader;
+    }
+
+    /// \brief Add a new node map reader command for the reader.
+    ///
+    /// Add a new node map reader command for the reader.
+    template <typename Map>
+    UndirGraphReader& readNodeMap(std::string name, Map& map) {
+      nodeset_reader.readNodeMap(name, map);
+      return *this;
+    }
+
+    template <typename Map>
+    UndirGraphReader& readNodeMap(std::string name, const Map& map) {
+      nodeset_reader.readNodeMap(name, map);
+      return *this;
+    }
+
+    /// \brief Add a new node map reader command for the reader.
+    ///
+    /// Add a new node map reader command for the reader.
+    template <typename Reader, typename Map>
+    UndirGraphReader& readNodeMap(std::string name, Map& map, 
+				  const Reader& reader = Reader()) {
+      nodeset_reader.readNodeMap(name, map, reader);
+      return *this;
+    }
+
+    template <typename Reader, typename Map>
+    UndirGraphReader& readNodeMap(std::string name, const Map& map, 
+				  const Reader& reader = Reader()) {
+      nodeset_reader.readNodeMap(name, map, reader);
+      return *this;
+    }
+
+    /// \brief Add a new node map skipper command for the reader.
+    ///
+    /// Add a new node map skipper command for the reader.
+    template <typename Reader>
+    UndirGraphReader& skipNodeMap(std::string name, 
+			     const Reader& reader = Reader()) {
+      nodeset_reader.skipNodeMap(name, reader);
+      return *this;
+    }
+
+    /// \brief Add a new undirected edge map reader command for the reader.
+    ///
+    /// Add a new undirected edge map reader command for the reader.
+    template <typename Map>
+    UndirGraphReader& readUndirEdgeMap(std::string name, Map& map) { 
+      undir_edgeset_reader.readUndirEdgeMap(name, map);
+      return *this;
+    }
+
+    template <typename Map>
+    UndirGraphReader& readUndirEdgeMap(std::string name, const Map& map) { 
+      undir_edgeset_reader.readUndirEdgeMap(name, map);
+      return *this;
+    }
+
+
+    /// \brief Add a new undirected edge map reader command for the reader.
+    ///
+    /// Add a new undirected edge map reader command for the reader.
+    template <typename Reader, typename Map>
+    UndirGraphReader& readUndirEdgeMap(std::string name, Map& map,
+				       const Reader& reader = Reader()) {
+      undir_edgeset_reader.readUndirEdgeMap(name, map, reader);
+      return *this;
+    }
+
+    template <typename Reader, typename Map>
+    UndirGraphReader& readUndirEdgeMap(std::string name, const Map& map,
+				       const Reader& reader = Reader()) {
+      undir_edgeset_reader.readUndirEdgeMap(name, map, reader);
+      return *this;
+    }
+
+    /// \brief Add a new undirected edge map skipper command for the reader.
+    ///
+    /// Add a new undirected edge map skipper command for the reader.
+    template <typename Reader>
+    UndirGraphReader& skipUndirEdgeMap(std::string name,
+				       const Reader& reader = Reader()) {
+      undir_edgeset_reader.skipUndirMap(name, reader);
+      return *this;
+    }
+
+
+    /// \brief Add a new edge map reader command for the reader.
+    ///
+    /// Add a new edge map reader command for the reader.
+    template <typename Map>
+    UndirGraphReader& readEdgeMap(std::string name, Map& map) { 
+      undir_edgeset_reader.readEdgeMap(name, map);
+      return *this;
+    }
+
+    template <typename Map>
+    UndirGraphReader& readEdgeMap(std::string name, const Map& map) { 
+      undir_edgeset_reader.readEdgeMap(name, map);
+      return *this;
+    }
+
+
+    /// \brief Add a new edge map reader command for the reader.
+    ///
+    /// Add a new edge map reader command for the reader.
+    template <typename Reader, typename Map>
+    UndirGraphReader& readEdgeMap(std::string name, Map& map,
+				       const Reader& reader = Reader()) {
+      undir_edgeset_reader.readEdgeMap(name, map, reader);
+      return *this;
+    }
+
+    template <typename Reader, typename Map>
+    UndirGraphReader& readEdgeMap(std::string name, const Map& map,
+				       const Reader& reader = Reader()) {
+      undir_edgeset_reader.readEdgeMap(name, map, reader);
+      return *this;
+    }
+
+    /// \brief Add a new edge map skipper command for the reader.
+    ///
+    /// Add a new edge map skipper command for the reader.
+    template <typename Reader>
+    UndirGraphReader& skipEdgeMap(std::string name,
+				       const Reader& reader = Reader()) {
+      undir_edgeset_reader.skipEdgeMap(name, reader);
+      return *this;
+    }
+
+    /// \brief Add a new labeled node reader for the reader.
+    ///
+    /// Add a new labeled node reader for the reader.
+    UndirGraphReader& readNode(std::string name, Node& node) {
+      node_reader.readNode(name, node);
+      return *this;
+    }
+
+    /// \brief Add a new labeled edge reader for the reader.
+    ///
+    /// Add a new labeled edge reader for the reader.
+    UndirGraphReader& readUndirEdge(std::string name, UndirEdge& edge) {
+      undir_edge_reader.readUndirEdge(name, edge);
+    }
+
+    /// \brief Add a new attribute reader command.
+    ///
+    ///  Add a new attribute reader command.
+    template <typename Value>
+    UndirGraphReader& readAttribute(std::string name, Value& value) {
+      attribute_reader.readAttribute(name, value);
+      return *this;
+    }
+    
+    /// \brief Add a new attribute reader command.
+    ///
+    ///  Add a new attribute reader command.
+    template <typename Reader, typename Value>
+    UndirGraphReader& readAttribute(std::string name, Value& value, 
+			       const Reader& reader) {
+      attribute_reader.readAttribute<Reader>(name, value, reader);
+      return *this;
+    }
+
+    /// \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;
+    }
+
+    /// \brief Executes the reader commands.
+    ///
+    /// Executes the reader commands.
+    void run() {
+      reader->run();
+    }
+
+  private:
+
+    LemonReader* reader;
+    bool own_reader;
+
+    DefaultSkipper skipper;
+
+    NodeSetReader<Graph, ReaderTraits> nodeset_reader;
+    UndirEdgeSetReader<Graph, ReaderTraits> undir_edgeset_reader;
+
+    NodeReader<Graph> node_reader;
+    UndirEdgeReader<Graph> undir_edge_reader;
+    
+    AttributeReader<ReaderTraits> attribute_reader;
+  };
+
+  /// \brief Read an undir graph from the input.
+  ///
+  /// Read an undir graph from the input.
+  /// \param is The input stream.
+  /// \param g The graph.
+  /// \param capacity The capacity map.
+  template<typename Graph, typename CapacityMap>
+  void readUndirGraph(std::istream& is, Graph &g, CapacityMap& capacity) {
+    UndirGraphReader<Graph> reader(is, g);
+    reader.readUndirEdgeMap("capacity", capacity);
+    reader.run();
+  }
+
+  /// \brief Read an undir graph from the input.
+  ///
+  /// Read an undir graph from the input.
+  /// \param is The input stream.
+  /// \param g The graph.
+  template<typename Graph>
+  void readUndirGraph(std::istream& is, Graph &g) {
+    UndirGraphReader<Graph> reader(is, g);
+    reader.run();
+  }
+
   /// @}
 }
 

Modified: hugo/trunk/src/lemon/graph_writer.h
==============================================================================
--- hugo/trunk/src/lemon/graph_writer.h	(original)
+++ hugo/trunk/src/lemon/graph_writer.h	Sat May 14 19:39:37 2005
@@ -52,8 +52,7 @@
   /// IdMap<ListGraph, Node> nodeIdMap;
   /// writer.writeNodeMap("id", nodeIdMap);
   ///
-  /// writer.writeNodeMap("x-coord", xCoordMap);
-  /// writer.writeNodeMap("y-coord", yCoordMap);
+  /// writer.writeNodeMap("coords", coords);
   /// writer.writeNodeMap("color", colorMap);
   /// \endcode
   ///
@@ -91,7 +90,7 @@
   /// \see QuotedStringWriter
   /// \see IdMap
   /// \see DescriptorMap
-  /// \see \ref GraphWriter
+  /// \see \ref GraphReader
   /// \see \ref graph-io-page
   /// \author Balazs Dezso
   template <typename _Graph, typename _WriterTraits = DefaultWriterTraits> 
@@ -110,9 +109,8 @@
     /// to the given stream.
     GraphWriter(std::ostream& _os, const Graph& _graph) 
       : writer(new LemonWriter(_os)), own_writer(true), 
-	graph(_graph), 
-	nodeset_writer(*writer, graph, std::string()),
-	edgeset_writer(*writer, graph, nodeset_writer, std::string()),
+	nodeset_writer(*writer, _graph, std::string()),
+	edgeset_writer(*writer, _graph, nodeset_writer, std::string()),
 	node_writer(*writer, nodeset_writer, std::string()),
 	edge_writer(*writer, edgeset_writer, std::string()),
 	attribute_writer(*writer, std::string()) {}
@@ -123,9 +121,8 @@
     /// to the given file.
     GraphWriter(const std::string& _filename, const Graph& _graph) 
       : writer(new LemonWriter(_filename)), own_writer(true), 
-	graph(_graph),
-	nodeset_writer(*writer, graph, std::string()),
-	edgeset_writer(*writer, graph, nodeset_writer, std::string()),
+	nodeset_writer(*writer, _graph, std::string()),
+	edgeset_writer(*writer, _graph, nodeset_writer, std::string()),
 	node_writer(*writer, nodeset_writer, std::string()),
 	edge_writer(*writer, edgeset_writer, std::string()),
 	attribute_writer(*writer, std::string()) {}
@@ -136,9 +133,8 @@
     /// to given LemonReader.
     GraphWriter(LemonWriter& _writer, const Graph& _graph)
       : writer(_writer), own_writer(false), 
-	graph(_graph),
-	nodeset_writer(*writer, graph, std::string()),
-	edgeset_writer(*writer, graph, nodeset_writer, std::string()),
+	nodeset_writer(*writer, _graph, std::string()),
+	edgeset_writer(*writer, _graph, nodeset_writer, std::string()),
 	node_writer(*writer, nodeset_writer, std::string()),
 	edge_writer(*writer, edgeset_writer, std::string()),
 	attribute_writer(*writer, std::string()) {}
@@ -156,7 +152,7 @@
     /// Add a new node map writer command for the writer.
     template <typename Map>
     GraphWriter& writeNodeMap(std::string name, const Map& map) {
-      nodeset_writer.writeMap(name, map);
+      nodeset_writer.writeNodeMap(name, map);
       return *this;
     }
 
@@ -165,8 +161,8 @@
     /// Add a new node map writer command for the writer.
     template <typename Writer, typename Map>
     GraphWriter& writeNodeMap(std::string name, const Map& map, 
-			     const Writer& writer = Writer()) {
-      nodeset_writer.writeMap(name, map, writer);
+			      const Writer& writer = Writer()) {
+      nodeset_writer.writeNodeMap(name, map, writer);
       return *this;
     }
 
@@ -176,7 +172,7 @@
     /// Add a new edge map writer command for the writer.
     template <typename Map>
     GraphWriter& writeEdgeMap(std::string name, const Map& map) { 
-      edgeset_writer.writeMap(name, map);
+      edgeset_writer.writeEdgeMap(name, map);
       return *this;
     }
 
@@ -186,8 +182,8 @@
     /// Add a new edge map writer command for the writer.
     template <typename Writer, typename Map>
     GraphWriter& writeEdgeMap(std::string name, const Map& map,
-			     const Writer& writer = Writer()) {
-      edgeset_writer.writeMap(name, map, writer);
+			      const Writer& writer = Writer()) {
+      edgeset_writer.writeEdgeMap(name, map, writer);
       return *this;
     }
 
@@ -247,8 +243,6 @@
     LemonWriter* writer;
     bool own_writer;
 
-    const Graph& graph;
-
     NodeSetWriter<Graph, WriterTraits> nodeset_writer;
     EdgeSetWriter<Graph, WriterTraits> edgeset_writer;
 
@@ -360,6 +354,279 @@
     writer.run();
   }
 
+  /// \brief The undirected graph writer class.
+  ///
+  /// The \c UndirGraphWriter class provides the undir graph output. To write 
+  /// a graph you should first give writing commands for the writer. You can 
+  /// declare write command as \c NodeMap, \c EdgeMap or \c UndirEdgeMap 
+  /// writing and labeled Node, Edge or UndirEdge writing.
+  ///
+  /// \code
+  /// UndirGraphWriter<UndirListGraph> writer(std::cout, graph);
+  /// \endcode
+  ///
+  /// The \c writeNodeMap() function declares a \c NodeMap writing 
+  /// command in the \c UndirGraphWriter. You should give as parameter 
+  /// the name of the map and the map object. The NodeMap writing 
+  /// command with name "id" should write a unique map because it 
+  /// is regarded as ID map.
+  ///
+  /// \code
+  /// IdMap<UndirListGraph, Node> nodeIdMap;
+  /// writer.writeNodeMap("id", nodeIdMap);
+  ///
+  /// writer.writeNodeMap("coords", coords);
+  /// writer.writeNodeMap("color", colorMap);
+  /// \endcode
+  ///
+  /// With the \c writeUndirEdgeMap() member function you can give an 
+  /// undirected edge map writing command similar to the NodeMaps.
+  ///
+  /// \code
+  /// DescriptorMap<ListGraph, Edge, ListGraph::EdgeMap<int> > 
+  ///   edgeDescMap(graph);
+  /// writer.writeUndirEdgeMap("descriptor", edgeDescMap);
+  ///
+  /// writer.writeUndirEdgeMap("weight", weightMap);
+  /// writer.writeUndirEdgeMap("label", labelMap);
+  /// \endcode
+  /// 
+  /// The EdgeMap handling is just a syntactical sugar. It writes
+  /// two undirected edge map with '+' and '-' prefix in the name.
+  ///
+  /// \code
+  /// writer.writeEdgeMap("capacity", capacityMap);
+  /// \endcode
+  ///
+  ///
+  /// With \c writeNode() and \c writeUndirEdge() functions you can 
+  /// point out nodes and undirected edges in the graph. By example, you can 
+  /// write out the source and target of the graph.
+  ///
+  /// \code
+  /// writer.writeNode("source", sourceNode);
+  /// writer.writeNode("target", targetNode);
+  ///
+  /// writer.writeUndirEdge("observed", undirEdge);
+  /// \endcode
+  ///
+  /// After you give all write commands you must call the \c run() member
+  /// function, which execute all the writer commands.
+  ///
+  /// \code
+  /// writer.run();
+  /// \endcode
+  ///
+  /// \see DefaultWriterTraits
+  /// \see QuotedStringWriter
+  /// \see IdMap
+  /// \see DescriptorMap
+  /// \see \ref GraphWriter
+  /// \see \ref graph-io-page
+  /// \author Balazs Dezso
+  template <typename _Graph, typename _WriterTraits = DefaultWriterTraits> 
+  class UndirGraphWriter {
+  public:
+    
+    typedef _Graph Graph;
+    typedef typename Graph::Node Node;
+    typedef typename Graph::Edge Edge;
+    typedef typename Graph::UndirEdge UndirEdge;
+
+    typedef _WriterTraits WriterTraits;
+
+    /// \brief Construct a new UndirGraphWriter.
+    ///
+    /// Construct a new UndirGraphWriter. It writes the given graph
+    /// to the given stream.
+    UndirGraphWriter(std::ostream& _os, const Graph& _graph) 
+      : writer(new LemonWriter(_os)), own_writer(true), 
+	nodeset_writer(*writer, _graph, std::string()),
+	undir_edgeset_writer(*writer, _graph, nodeset_writer, std::string()),
+	node_writer(*writer, nodeset_writer, std::string()),
+	undir_edge_writer(*writer, undir_edgeset_writer, std::string()),
+	attribute_writer(*writer, std::string()) {}
+
+    /// \brief Construct a new UndirGraphWriter.
+    ///
+    /// Construct a new UndirGraphWriter. It writes into the given graph
+    /// to the given file.
+    UndirGraphWriter(const std::string& _filename, const Graph& _graph) 
+      : writer(new LemonWriter(_filename)), own_writer(true), 
+	nodeset_writer(*writer, _graph, std::string()),
+	undir_edgeset_writer(*writer, _graph, nodeset_writer, std::string()),
+	node_writer(*writer, nodeset_writer, std::string()),
+	undir_edge_writer(*writer, undir_edgeset_writer, std::string()),
+	attribute_writer(*writer, std::string()) {}
+
+    /// \brief Construct a new UndirGraphWriter.
+    ///
+    /// Construct a new UndirGraphWriter. It writes into the given graph
+    /// to given LemonReader.
+    UndirGraphWriter(LemonWriter& _writer, const Graph& _graph)
+      : writer(_writer), own_writer(false), 
+	nodeset_writer(*writer, _graph, std::string()),
+	undir_edgeset_writer(*writer, _graph, nodeset_writer, std::string()),
+	node_writer(*writer, nodeset_writer, std::string()),
+	undir_edge_writer(*writer, undir_edgeset_writer, std::string()),
+	attribute_writer(*writer, std::string()) {}
+
+    /// \brief Destruct the graph writer.
+    ///
+    /// Destruct the graph writer.
+    ~UndirGraphWriter() {
+      if (own_writer) 
+	delete writer;
+    }
+
+    /// \brief Add a new node map writer command for the writer.
+    ///
+    /// Add a new node map writer command for the writer.
+    template <typename Map>
+    UndirGraphWriter& writeNodeMap(std::string name, const Map& map) {
+      nodeset_writer.writeNodeMap(name, map);
+      return *this;
+    }
+
+    /// \brief Add a new node map writer command for the writer.
+    ///
+    /// Add a new node map writer command for the writer.
+    template <typename Writer, typename Map>
+    UndirGraphWriter& writeNodeMap(std::string name, const Map& map, 
+			      const Writer& writer = Writer()) {
+      nodeset_writer.writeNodeMap(name, map, writer);
+      return *this;
+    }
+
+    /// \brief Add a new edge map writer command for the writer.
+    ///
+    /// Add a new edge map writer command for the writer.
+    template <typename Map>
+    UndirGraphWriter& writeEdgeMap(std::string name, const Map& map) { 
+      undir_edgeset_writer.writeEdgeMap(name, map);
+      return *this;
+    }
+
+    /// \brief Add a new edge map writer command for the writer.
+    ///
+    /// Add a new edge map writer command for the writer.
+    template <typename Writer, typename Map>
+    UndirGraphWriter& writeEdgeMap(std::string name, const Map& map,
+				   const Writer& writer = Writer()) {
+      undir_edgeset_writer.writeEdgeMap(name, map, writer);
+      return *this;
+    }
+
+    /// \brief Add a new undirected edge map writer command for the writer.
+    ///
+    /// Add a new undirected edge map writer command for the writer.
+    template <typename Map>
+    UndirGraphWriter& writeUndirEdgeMap(std::string name, const Map& map) { 
+      undir_edgeset_writer.writeUndirEdgeMap(name, map);
+      return *this;
+    }
+
+    /// \brief Add a new undirected edge map writer command for the writer.
+    ///
+    /// Add a new edge undirected map writer command for the writer.
+    template <typename Writer, typename Map>
+    UndirGraphWriter& writeUndirEdgeMap(std::string name, const Map& map,
+					const Writer& writer = Writer()) {
+      undir_edgeset_writer.writeUndirEdgeMap(name, map, writer);
+      return *this;
+    }
+
+    /// \brief Add a new labeled node writer for the writer.
+    ///
+    /// Add a new labeled node writer for the writer.
+    UndirGraphWriter& writeNode(std::string name, const Node& node) {
+      node_writer.writeNode(name, node);
+      return *this;
+    }
+
+    /// \brief Add a new labeled edge writer for the writer.
+    ///
+    /// Add a new labeled edge writer for the writer.
+    UndirGraphWriter& writeUndirEdge(std::string name, const UndirEdge& edge) {
+      undir_edge_writer.writeUndirEdge(name, edge);
+    }
+
+    /// \brief Add a new attribute writer command.
+    ///
+    ///  Add a new attribute writer command.
+    template <typename Value>
+    UndirGraphWriter& writeAttribute(std::string name, const Value& value) {
+      attribute_writer.writeAttribute(name, value);
+      return *this;
+    }
+    
+    /// \brief Add a new attribute writer command.
+    ///
+    ///  Add a new attribute writer command.
+    template <typename Writer, typename Value>
+    UndirGraphWriter& writeAttribute(std::string name, const Value& value, 
+			       const Writer& writer) {
+      attribute_writer.writeAttribute<Writer>(name, value, writer);
+      return *this;
+    }
+
+    /// \brief Conversion operator to LemonWriter.
+    ///
+    /// Conversion operator to LemonWriter. It make possible
+    /// to access the encapsulated \e LemonWriter, this way
+    /// you can attach to this writer new instances of 
+    /// \e LemonWriter::SectionWriter.
+    operator LemonWriter&() {
+      return *writer;
+    }
+
+    /// \brief Executes the writer commands.
+    ///
+    /// Executes the writer commands.
+    void run() {
+      writer->run();
+    }
+
+  private:
+
+    LemonWriter* writer;
+    bool own_writer;
+
+    NodeSetWriter<Graph, WriterTraits> nodeset_writer;
+    UndirEdgeSetWriter<Graph, WriterTraits> undir_edgeset_writer;
+
+    NodeWriter<Graph> node_writer;
+    UndirEdgeWriter<Graph> undir_edge_writer;
+    
+    AttributeWriter<WriterTraits> attribute_writer;
+  };
+
+
+  /// \brief Write an undirected graph to the output.
+  ///
+  /// Write an undirected graph to the output.
+  /// \param os The output stream.
+  /// \param g The graph.
+  /// \param capacity The capacity undirected map.
+  template<typename Graph, typename CapacityMap>
+  void writeUndirGraph(std::ostream& os, const Graph &g, 
+		       const CapacityMap& capacity) {
+    UndirGraphWriter<Graph> writer(os, g);
+    writer.writeUndirEdgeMap("capacity", capacity);
+    writer.run();
+  }
+
+  /// \brief Write an undirected graph to the output.
+  ///
+  /// Write an undirected graph to the output.
+  /// \param os The output stream.
+  /// \param g The graph.
+  template<typename Graph>
+  void writeUndirGraph(std::ostream& os, const Graph &g) {
+    UndirGraphWriter<Graph> writer(os, g);
+    writer.run();
+  }
+
   /// @}
 
 }

Modified: hugo/trunk/src/lemon/lemon_reader.h
==============================================================================
--- hugo/trunk/src/lemon/lemon_reader.h	(original)
+++ hugo/trunk/src/lemon/lemon_reader.h	Sat May 14 19:39:37 2005
@@ -18,9 +18,11 @@
 ///\file
 ///\brief Lemon Format reader.
 
+
 #ifndef LEMON_LEMON_READER_H
 #define LEMON_LEMON_READER_H
 
+
 #include <iostream>
 #include <fstream>
 #include <string>
@@ -30,11 +32,61 @@
 #include <memory>
 
 #include <lemon/error.h>
+#include <lemon/graph_utils.h>
+#include <lemon/utility.h>
 #include <lemon/bits/item_reader.h>
 
 
 namespace lemon {
 
+  namespace _reader_bits {
+  
+    template <typename T>
+    bool operator<(T, T) {
+      throw DataFormatError("Id is not comparable");
+    }
+
+    template <typename T>
+    struct Less {
+      bool operator()(const T& p, const T& q) const {
+	return p < q;
+      }
+    };
+
+    template <typename M1, typename M2>
+    class WriteComposeMap {
+    public:
+      typedef True NeedCopy;
+      
+      typedef typename M2::Key Key;
+      typedef typename M1::Value Value;
+
+      WriteComposeMap(typename SmartParameter<M1>::Type _m1, const M2& _m2) 
+	: m1(_m1), m2(_m2) {}
+      
+      void set(const Key& key, const Value& value) {
+	m1.set(m2[key], value);
+      }
+
+    private:
+      
+      typename SmartReference<M1>::Type m1;
+      typename SmartConstReference<M2>::Type m2;
+      
+    };
+
+    template <typename M1, typename M2>
+    WriteComposeMap<M1, M2> writeComposeMap(M1& m1, const M2& m2) {
+      return WriteComposeMap<M1, M2>(m1, m2);
+    }
+
+    template <typename M1, typename M2>
+    WriteComposeMap<M1, M2> writeComposeMap(const M1& m1, const M2& m2) {
+      return WriteComposeMap<M1, M2>(m1, m2);
+    }
+  
+  }
+
   /// \ingroup io_group
   /// \brief Lemon Format reader class.
   /// 
@@ -338,8 +390,6 @@
       virtual InverterBase<_Item>* getInverter() {
 	return this;
       }
-
-
     };
 
     template <typename _Item, typename _Map, typename _Reader>
@@ -349,13 +399,15 @@
       typedef _Reader Reader;
       typedef typename Reader::Value Value;
       typedef _Map Map;
-      typedef std::map<Value, Item> Inverse;
+      typedef std::map<Value, Item, 
+		       typename _reader_bits::template Less<Value> > Inverse;
 
-      Map& map;
+      typename SmartReference<Map>::Type map;
       Reader reader;
       Inverse inverse;
 
-      MapReaderInverter(Map& _map, const Reader& _reader) 
+      MapReaderInverter(typename SmartParameter<Map>::Type _map,
+			const Reader& _reader) 
 	: map(_map), reader(_reader) {}
 
       virtual ~MapReaderInverter() {}
@@ -382,7 +434,6 @@
 	  throw DataFormatError("Invalid ID error");
 	}
       }      
-
     };
 
     template <typename _Item, typename _Reader>
@@ -391,7 +442,8 @@
       typedef _Item Item;
       typedef _Reader Reader;
       typedef typename Reader::Value Value;
-      typedef std::map<Value, Item> Inverse;
+      typedef std::map<Value, Item, 
+		       typename _reader_bits::template Less<Value> > Inverse;
 
       Reader reader;
 
@@ -426,8 +478,6 @@
       Inverse inverse;
     };
 
-    // Readers
-
     template <typename _Item>    
     class ReaderBase {
     public:
@@ -447,10 +497,11 @@
       typedef typename Reader::Value Value;
       typedef _Item Item;
       
-      Map& map;
+      typename SmartReference<Map>::Type map;
       Reader reader;
 
-      MapReader(Map& _map, const Reader& _reader) 
+      MapReader(typename SmartParameter<Map>::Type _map, 
+		const Reader& _reader) 
 	: map(_map), reader(_reader) {}
 
       virtual ~MapReader() {}
@@ -569,7 +620,8 @@
     /// attach it into the given LemonReader. The nodeset reader will
     /// add the readed nodes to the given Graph. The reader will read
     /// the section when the \c section_id and the \c _id are the same. 
-    NodeSetReader(LemonReader& _reader, Graph& _graph, 
+    NodeSetReader(LemonReader& _reader, 
+		  typename SmartParameter<Graph>::Type _graph, 
 		  const std::string& _id = std::string(),
 		  const DefaultSkipper& _skipper = DefaultSkipper()) 
       : Parent(_reader), graph(_graph), id(_id), skipper(_skipper) {} 
@@ -595,17 +647,43 @@
     ///
     /// Add a new node map reader command for the reader.
     template <typename Map>
-    NodeSetReader& readMap(std::string name, Map& map) {
-      return readMap<typename Traits::
-	template Reader<typename Map::Value>, Map>(name, map);
+    NodeSetReader& readNodeMap(std::string name, Map& map) {
+      return _readMap<
+	typename Traits::template Reader<typename Map::Value>, Map,
+	typename SmartParameter<Map>::Type>(name, map);
+    }
+
+    template <typename Map>
+    NodeSetReader& readNodeMap(std::string name, const Map& map) {
+      return _readMap<
+	typename Traits::template Reader<typename Map::Value>, Map,
+	typename SmartParameter<Map>::Type>(name, map);
     }
 
     /// \brief Add a new node map reader command for the reader.
     ///
     /// Add a new node map reader command for the reader.
     template <typename Reader, typename Map>
-    NodeSetReader& readMap(std::string name, Map& map, 
-			     const Reader& reader = Reader()) {
+    NodeSetReader& readNodeMap(std::string name, Map& map, 
+			       const Reader& reader = Reader()) {
+      return _readMap<
+	typename Traits::template Reader<typename Map::Value>, Map,
+	typename SmartParameter<Map>::Type>(name, map, reader);
+    }
+
+    template <typename Reader, typename Map>
+    NodeSetReader& readNodeMap(std::string name, const Map& map, 
+			       const Reader& reader = Reader()) {
+      return _readMap<
+	typename Traits::template Reader<typename Map::Value>, Map, 
+	typename SmartParameter<Map>::Type>(name, map, reader);
+    }
+
+  private:
+
+    template <typename Reader, typename Map, typename MapParameter>
+    NodeSetReader& _readMap(std::string name, MapParameter map, 
+			    const Reader& reader = Reader()) {
       if (readers.find(name) != readers.end()) {
 	ErrorMessage msg;
 	msg << "Multiple read rule for node map: " << name;
@@ -616,11 +694,13 @@
       return *this;
     }
 
+  public:
+
     /// \brief Add a new node map skipper command for the reader.
     ///
     /// Add a new node map skipper command for the reader.
     template <typename Reader>
-    NodeSetReader& skipMap(std::string name, 
+    NodeSetReader& skipNodeMap(std::string name, 
 			   const Reader& reader = Reader()) {
       if (readers.find(name) != readers.end()) {
 	ErrorMessage msg;
@@ -636,7 +716,7 @@
     /// \brief Gives back true when the SectionReader can process 
     /// the section with the given header line.
     ///
-    /// It gives back true when the header line starts with \c @nodeset,
+    /// It gives back true when the header line starts with \c \@nodeset,
     /// and the header line's id and the nodeset's id are the same.
     virtual bool header(const std::string& line) {
       std::istringstream ls(line);
@@ -690,7 +770,7 @@
     ///
     /// It reads an id from the stream and gives back which node belongs to
     /// it. It is possible only if there was read an "id" named map.
-    typename Graph::Node readId(std::istream& is) const {
+    Item readId(std::istream& is) const {
       return inverter->read(is);
     } 
 
@@ -699,7 +779,7 @@
     typedef std::map<std::string, ReaderBase<Item>*> MapReaders;
     MapReaders readers;
    
-    Graph& graph;   
+    typename SmartReference<Graph>::Type graph;   
     std::string id;
     SkipReader<Item, DefaultSkipper> skipper;
 
@@ -714,8 +794,9 @@
   /// \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.
+  /// with white spaces. Each next lines describes an edge in the edgeset. The
+  /// line contains the source and the target nodes' id and the mapped 
+  /// values for each map.
   ///
   /// If the edgeset contains an \c "id" named map then it will be regarded
   /// as id map. This map should contain only unique values and when the 
@@ -746,7 +827,8 @@
     /// The reader will read the section only if the \c _id and the 
     /// \c edgset_id are the same. 
     template <typename NodeIdReader>
-    EdgeSetReader(LemonReader& _reader, Graph& _graph, 
+    EdgeSetReader(LemonReader& _reader, 
+		  typename SmartParameter<Graph>::Type _graph, 
 		  const NodeIdReader& _nodeIdReader, 
 		  const std::string& _id = std::string(),
 		  const DefaultSkipper& _skipper = DefaultSkipper()) 
@@ -774,17 +856,43 @@
     ///
     /// Add a new edge map reader command for the reader.
     template <typename Map>
-    EdgeSetReader& readMap(std::string name, Map& map) {
-      return readMap<typename Traits::
-	template Reader<typename Map::Value>, Map>(name, map);
+    EdgeSetReader& readEdgeMap(std::string name, Map& map) {
+      return _readMap<
+	typename Traits::template Reader<typename Map::Value>, Map,
+	typename SmartParameter<Map>::Type>(name, map);
+    }
+
+    template <typename Map>
+    EdgeSetReader& readEdgeMap(std::string name, const Map& map) {
+      return _readMap<
+	typename Traits::template Reader<typename Map::Value>, Map,
+	typename SmartParameter<Map>::Type>(name, map);
     }
 
     /// \brief Add a new edge map reader command for the reader.
     ///
     /// Add a new edge map reader command for the reader.
     template <typename Reader, typename Map>
-    EdgeSetReader& readMap(std::string name, Map& map, 
-			     const Reader& reader = Reader()) {
+    EdgeSetReader& readEdgeMap(std::string name, Map& map, 
+			   const Reader& reader = Reader()) {
+      return _readMap<
+	typename Traits::template Reader<typename Map::Value>, Map,
+	typename SmartParameter<Map>::Type>(name, map, reader);
+    }
+
+    template <typename Reader, typename Map>
+    EdgeSetReader& readEdgeMap(std::string name, const Map& map, 
+			       const Reader& reader = Reader()) {
+      return _readMap<
+	typename Traits::template Reader<typename Map::Value>, Map,
+	typename SmartParameter<Map>::Type>(name, map, reader);
+    }
+
+  private:
+
+    template <typename Reader, typename Map, typename MapParameter>
+    EdgeSetReader& _readMap(std::string name, MapParameter map, 
+			    const Reader& reader = Reader()) {
       if (readers.find(name) != readers.end()) {
 	ErrorMessage msg;
 	msg << "Multiple read rule for edge map: " << name;
@@ -795,15 +903,17 @@
       return *this;
     }
 
+  public:
+
     /// \brief Add a new edge map skipper command for the reader.
     ///
     /// Add a new edge map skipper command for the reader.
     template <typename Reader>
-    EdgeSetReader& skipMap(std::string name, 
-			   const Reader& reader = Reader()) {
+    EdgeSetReader& skipEdgeMap(std::string name, 
+			       const Reader& reader = Reader()) {
       if (readers.find(name) != readers.end()) {
 	ErrorMessage msg;
-	msg << "Multiple read rule for node map: " << name;
+	msg << "Multiple read rule for edge map: " << name;
 	throw IOParameterError(msg.message());
       }
       readers.insert(make_pair(name, new SkipReader<Item, Reader>(reader)));
@@ -815,7 +925,7 @@
     /// \brief Gives back true when the SectionReader can process 
     /// the section with the given header line.
     ///
-    /// It gives back true when the header line starts with \c @edgeset,
+    /// It gives back true when the header line starts with \c \@edgeset,
     /// and the header line's id and the edgeset's id are the same.
     virtual bool header(const std::string& line) {
       std::istringstream ls(line);
@@ -871,7 +981,7 @@
     ///
     /// It reads an id from the stream and gives back which edge belongs to
     /// it. It is possible only if there was read an "id" named map.
-    typename Graph::Edge readId(std::istream& is) const {
+    Item readId(std::istream& is) const {
       return inverter->read(is);
     } 
 
@@ -880,7 +990,281 @@
     typedef std::map<std::string, ReaderBase<Item>*> MapReaders;
     MapReaders readers;
    
-    Graph& graph;   
+    typename SmartReference<Graph>::Type graph;   
+    std::string id;
+    SkipReader<Item, DefaultSkipper> skipper;
+
+    std::auto_ptr<InverterBase<Item> > inverter;
+    std::auto_ptr<IdReaderBase<typename Graph::Node> > nodeIdReader;
+  };
+
+  /// \ingroup io_group
+  /// \brief SectionReader for reading a undirected graph's edgeset.
+  ///
+  /// The lemon format can store multiple undirected edgesets with several 
+  /// maps. The undirected edgeset section's header line is \c \@undiredgeset 
+  /// \c undiredgeset_id, but the \c undiredgeset_id may be empty.
+  ///
+  /// The first line of the section contains the names of the maps separated
+  /// with white spaces. Each next lines describes an edge in the edgeset. The
+  /// line contains the connected nodes' id and the mapped values for each map.
+  ///
+  /// The section can handle the directed as a syntactical sugar. Two
+  /// undirected edge map describes one directed edge map. This two maps
+  /// are the forward map and the backward map and the names of this map
+  /// is near the same just with a prefix \c '+' or \c '-' character 
+  /// difference.
+  ///
+  /// If the edgeset contains an \c "id" named map then it will be regarded
+  /// as id map. This map should contain only unique values and when the 
+  /// \c readId() member will read a value from the given stream it will
+  /// give back that undiricted edge which is mapped to this value.
+  ///
+  /// The undirected edgeset reader needs a node id reader to identify which 
+  /// nodes have to be connected. If a NodeSetReader reads an "id" named map,
+  /// it will be able to resolve the nodes by ids.
+  ///
+  /// \relates LemonReader
+  template <typename _Graph, typename _Traits = DefaultReaderTraits>
+  class UndirEdgeSetReader : public CommonSectionReaderBase {
+    typedef CommonSectionReaderBase Parent;
+  public:
+
+    typedef _Graph Graph;
+    typedef _Traits Traits;
+    typedef typename Graph::UndirEdge Item;
+    typedef typename Traits::Skipper DefaultSkipper;
+
+    /// \brief Constructor.
+    ///
+    /// Constructor for UndirEdgeSetReader. It creates the UndirEdgeSetReader 
+    /// and attach it into the given LemonReader. The undirected edgeset 
+    /// reader will add the readed undirected edges to the given Graph. It 
+    /// will use the given node id reader to read the source and target 
+    /// nodes of the edges. The reader will read the section only if the 
+    /// \c _id and the \c undiredgset_id are the same. 
+    template <typename NodeIdReader>
+    UndirEdgeSetReader(LemonReader& _reader, 
+		       typename SmartParameter<Graph>::Type _graph, 
+		       const NodeIdReader& _nodeIdReader, 
+		       const std::string& _id = std::string(),
+		       const DefaultSkipper& _skipper = DefaultSkipper()) 
+      : Parent(_reader), graph(_graph), id(_id), skipper(_skipper),
+	nodeIdReader(new IdReader<typename Graph::Node, NodeIdReader>
+		     (_nodeIdReader)) {} 
+
+    /// \brief Destructor.
+    ///
+    /// Destructor for UndirEdgeSetReader.
+    virtual ~UndirEdgeSetReader() {
+      for (typename MapReaders::iterator it = readers.begin(); 
+	   it != readers.end(); ++it) {
+	delete it->second;
+      }
+    }
+
+  private:
+    UndirEdgeSetReader(const UndirEdgeSetReader&);
+    void operator=(const UndirEdgeSetReader&);
+
+  public:
+
+    /// \brief Add a new undirected edge map reader command for the reader.
+    ///
+    /// Add a new edge undirected map reader command for the reader.
+    template <typename Map>
+    UndirEdgeSetReader& readUndirEdgeMap(std::string name, Map& map) {
+      return _readMap<
+	typename Traits::template Reader<typename Map::Value>, Map, 
+	typename SmartParameter<Map>::Type>(name, map);
+    }
+
+    template <typename Map>
+    UndirEdgeSetReader& readUndirEdgeMap(std::string name, const Map& map) {
+      return _readMap<
+	typename Traits::template Reader<typename Map::Value>, Map, 
+	typename SmartParameter<Map>::Type>(name, map);
+    }
+
+    /// \brief Add a new undirected edge map reader command for the reader.
+    ///
+    /// Add a new edge undirected map reader command for the reader.
+    template <typename Reader, typename Map>
+    UndirEdgeSetReader& readUndirEdgeMap(std::string name, Map& map, 
+					 const Reader& reader = Reader()) {
+      return _readMap<Reader, Map, typename SmartParameter<Map>::Type>
+	(name, map, reader);
+    }
+
+    template <typename Reader, typename Map>
+    UndirEdgeSetReader& readUndirEdgeMap(std::string name, const Map& map, 
+					 const Reader& reader = Reader()) {
+      return _readMap<Reader, Map, typename SmartParameter<Map>::Type >
+	(name, map, reader);
+    }
+
+  private:
+
+    template <typename Reader, typename Map, typename MapParameter>
+    UndirEdgeSetReader& _readMap(std::string name, MapParameter map,
+				 const Reader& reader = Reader()) {
+      if (readers.find(name) != readers.end()) {
+	ErrorMessage msg;
+	msg << "Multiple read rule for edge map: " << name;
+	throw IOParameterError(msg.message());
+      }
+      readers.insert(
+	make_pair(name, new MapReader<Item, Map, Reader>(map, reader)));
+      return *this;
+    }
+
+  public:
+
+    /// \brief Add a new undirected edge map skipper command for the reader.
+    ///
+    /// Add a new undirected edge map skipper command for the reader.
+    template <typename Reader>
+    UndirEdgeSetReader& skipUndirEdgeMap(std::string name, 
+					 const Reader& reader = Reader()) {
+      if (readers.find(name) != readers.end()) {
+	ErrorMessage msg;
+	msg << "Multiple read rule for node map: " << name;
+	throw IOParameterError(msg.message());
+      }
+      readers.insert(make_pair(name, new SkipReader<Item, Reader>(reader)));
+      return *this;
+    }
+
+    /// \brief Add a new directed edge map reader command for the reader.
+    ///
+    /// Add a new directed edge map reader command for the reader.
+    template <typename Map>
+    UndirEdgeSetReader& readEdgeMap(std::string name, Map& map) {
+      return _readDirMap<
+	typename Traits::template Reader<typename Map::Value>, Map,
+	typename SmartParameter<Map>::Type>(name, map);
+    }
+
+    template <typename Map>
+    UndirEdgeSetReader& readEdgeMap(std::string name, const Map& map) {
+      return _readDirMap<
+	typename Traits::template Reader<typename Map::Value>, Map,
+	typename SmartParameter<Map>::Type>(name, map);
+    }
+
+    /// \brief Add a new directed edge map reader command for the reader.
+    ///
+    /// Add a new directed edge map reader command for the reader.
+    template <typename Reader, typename Map>
+    UndirEdgeSetReader& readEdgeMap(std::string name, Map& map, 
+				    const Reader& reader = Reader()) {
+      return _readDirMap<Reader, Map, typename SmartParameter<Map>::Type>
+	(name, map, reader);
+    }
+
+    template <typename Reader, typename Map>
+    UndirEdgeSetReader& readEdgeMap(std::string name, const Map& map, 
+				    const Reader& reader = Reader()) {
+      return _readDirMap<Reader, Map, typename SmartParameter<Map>::Type>
+	(name, map, reader);
+    }
+
+  private:
+
+    template <typename Reader, typename Map, typename MapParameter>
+    UndirEdgeSetReader& _readDirMap(std::string name, MapParameter map,
+				    const Reader& reader = Reader()) {
+      readMap("+" + name, 
+	      _reader_bits::writeComposeMap(map, forwardMap(graph)), reader);
+      readMap("-" + name, 
+	      _reader_bits::writeComposeMap(map, backwardMap(graph)), reader);
+      return *this;      
+    }
+
+  public:
+
+    /// \brief Add a new directed edge map skipper command for the reader.
+    ///
+    /// Add a new directed edge map skipper command for the reader.
+    template <typename Reader>
+    UndirEdgeSetReader& skipEdgeMap(std::string name, 
+				    const Reader& reader = Reader()) {
+      skipMap("+" + name, reader);
+      skipMap("-" + name, reader);
+      return *this;
+    }
+
+  protected:
+
+    /// \brief Gives back true when the SectionReader can process 
+    /// the section with the given header line.
+    ///
+    /// It gives back true when the header line starts with \c \@undiredgeset,
+    /// 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;
+      std::string name;
+      ls >> command >> name;
+      return command == "@undiredgeset" && name == id;
+    }
+
+    /// \brief Reader function of the section.
+    ///
+    /// It reads the content of the section.
+    virtual void read(std::istream& is) {
+      std::vector<ReaderBase<Item>* > index;
+      std::string line;
+
+      getline(is, line);
+      std::istringstream ls(line);	
+      while (ls >> id) {
+	typename MapReaders::iterator it = readers.find(id);
+	if (it != readers.end()) {
+	  index.push_back(it->second);
+	} else {
+	  index.push_back(&skipper);
+	}
+	if (id == "id" && inverter.get() == 0) {
+	  inverter.reset(index.back()->getInverter());
+	  index.back() = inverter.get();
+	}
+      }
+      while (getline(is, line)) {	
+	std::istringstream ls(line);
+	typename Graph::Node from = nodeIdReader->read(ls);
+	typename Graph::Node to = nodeIdReader->read(ls);
+	typename Graph::UndirEdge edge = graph.addEdge(from, to);
+	for (int i = 0; i < (int)index.size(); ++i) {
+	  index[i]->read(ls, edge);
+	}
+      }
+    }
+
+  public:
+
+    /// \brief Returns true if the edgeset can give back the edge by its id.
+    ///
+    /// Returns true if the edgeset can give back the undirected edge by its 
+    /// id. It is possible only if an "id" named map was read.
+    bool isIdReader() const {
+      return inverter.get() != 0;
+    }
+
+    /// \brief Gives back the undirected edge by its id.
+    ///
+    /// It reads an id from the stream and gives back which undirected edge 
+    /// belongs to it. It is possible only if there was read an "id" named map.
+    Item readId(std::istream& is) const {
+      return inverter->read(is);
+    } 
+
+  private:
+
+    typedef std::map<std::string, ReaderBase<Item>*> MapReaders;
+    MapReaders readers;
+   
+    typename SmartReference<Graph>::Type graph;   
     std::string id;
     SkipReader<Item, DefaultSkipper> skipper;
 
@@ -945,7 +1329,7 @@
     /// \brief Gives back true when the SectionReader can process 
     /// the section with the given header line.
     ///
-    /// It gives back true when the header line start with \c @nodes,
+    /// 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);
@@ -1002,7 +1386,7 @@
     /// Constructor for EdgeReader. It creates the EdgeReader and
     /// attach it into the given LemonReader. It will use the given
     /// edge id reader to give back the edges. The reader will read the 
-    /// section only if the \c _id and the \c nodes_id are the same. 
+    /// section only if the \c _id and the \c edges_id are the same. 
     template <typename _IdReader>
     EdgeReader(LemonReader& _reader, const _IdReader& _idReader, 
 	       const std::string& _id = std::string()) 
@@ -1036,7 +1420,100 @@
     /// \brief Gives back true when the SectionReader can process 
     /// the section with the given header line.
     ///
-    /// It gives back true when the header line start with \c @edges,
+    /// It gives back true when the header line start with \c \@edges,
+    /// and the header line's id and the reader's id are the same.
+    virtual bool header(const std::string& line) {
+      std::istringstream ls(line);
+      std::string command;
+      std::string name;
+      ls >> command >> name;
+      return command == "@edges" && name == id;
+    }
+
+    /// \brief Reader function of the section.
+    ///
+    /// It reads the content of the section.
+    virtual void read(std::istream& is) {
+      std::string line;
+      while (getline(is, line)) {
+	std::istringstream ls(line);
+	std::string id;
+	ls >> id;
+	typename ItemReaders::iterator it = readers.find(id);
+	if (it != readers.end()) {
+	  *(it->second) = idReader->read(ls); 
+	}	
+      }
+    }
+    
+  private:
+
+    std::string id;
+
+    typedef std::map<std::string, Item*> ItemReaders;
+    ItemReaders readers;
+    std::auto_ptr<IdReaderBase<Item> > idReader;
+  };
+
+  /// \ingroup io_group
+  /// \brief SectionReader for reading labeled undirected edges.
+  ///
+  /// The undirected edges section's header line is \c \@undiredges 
+  /// \c undiredges_id, but the \c undiredges_id may be empty.
+  ///
+  /// Each line in the section contains the name of the undirected edge 
+  /// and then the undirected edge id. 
+  ///
+  /// \relates LemonReader
+  template <typename _Graph>
+  class UndirEdgeReader : public CommonSectionReaderBase {
+    typedef CommonSectionReaderBase Parent;
+    typedef _Graph Graph;
+    typedef typename Graph::UndirEdge Item;
+  public:
+    
+    /// \brief Constructor.
+    ///
+    /// Constructor for UndirEdgeReader. It creates the UndirEdgeReader and
+    /// attach it into the given LemonReader. It will use the given
+    /// undirected edge id reader to give back the edges. The reader will 
+    /// read the section only if the \c _id and the \c undiredges_id are 
+    /// the same. 
+    template <typename _IdReader>
+    UndirEdgeReader(LemonReader& _reader, const _IdReader& _idReader, 
+	       const std::string& _id = std::string()) 
+      : Parent(_reader), id(_id), 
+	idReader(new IdReader<typename Graph::UndirEdge, _IdReader>(_idReader))
+    {} 
+
+    /// \brief Destructor.
+    ///
+    /// Destructor for UndirEdgeReader.
+    virtual ~UndirEdgeReader() {}
+  private:
+    UndirEdgeReader(const UndirEdgeReader&);
+    void operator=(const UndirEdgeReader&);
+
+  public:
+
+    /// \brief Add an undirected edge reader command for the UndirEdgeReader.
+    ///
+    /// Add an undirected edge reader command for the UndirEdgeReader.
+    void readUndirEdge(const std::string& name, Item& item) {
+      if (readers.find(name) != readers.end()) {
+	ErrorMessage msg;
+	msg << "Multiple read rule for edge: " << name;
+	throw IOParameterError(msg.message());
+      }
+      readers.insert(make_pair(name, &item));
+    }
+
+  protected:
+
+    /// \brief Gives back true when the SectionReader can process 
+    /// the section with the given header line.
+    ///
+    /// It gives back true when the header line start with \c \@edges,
     /// and the header line's id and the reader's id are the same.
     virtual bool header(const std::string& line) {
       std::istringstream ls(line);
@@ -1141,7 +1618,7 @@
     /// \brief Gives back true when the SectionReader can process 
     /// the section with the given header line.
     ///
-    /// It gives back true when the header line start with \c @attributes,
+    /// It gives back true when the header line start with \c \@attributes,
     /// and the header line's id and the attributeset's id are the same.
     bool header(const std::string& line) {
       std::istringstream ls(line);
@@ -1174,6 +1651,5 @@
     Readers readers;  
   };
 
-
 }
 #endif

Modified: hugo/trunk/src/lemon/lemon_writer.h
==============================================================================
--- hugo/trunk/src/lemon/lemon_writer.h	(original)
+++ hugo/trunk/src/lemon/lemon_writer.h	Sat May 14 19:39:37 2005
@@ -31,7 +31,10 @@
 
 #include <lemon/error.h>
 #include <lemon/invalid.h>
+#include <lemon/graph_utils.h>
 #include <lemon/bits/item_writer.h>
+#include <lemon/utility.h>
+#include <lemon/maps.h>
 
 
 namespace lemon {
@@ -163,8 +166,6 @@
     CommonSectionWriterBase(LemonWriter& _writer) 
       : Parent(_writer) {}
 
-    // Writers
-
     template <typename _Item>    
     class WriterBase {
     public:
@@ -184,7 +185,7 @@
       typedef typename Writer::Value Value;
       typedef _Item Item;
       
-      const Map& map;
+      typename SmartConstReference<Map>::Type map;
       Writer writer;
 
       MapWriter(const Map& _map, const Writer& _writer) 
@@ -306,8 +307,8 @@
     ///
     /// Add a new node map writer command for the writer.
     template <typename Map>
-    NodeSetWriter& writeMap(std::string name, const Map& map) {
-      return writeMap<typename Traits::
+    NodeSetWriter& writeNodeMap(std::string name, const Map& map) {
+      return writeNodeMap<typename Traits::
 	template Writer<typename Map::Value>, Map>(name, map);
     }
 
@@ -315,8 +316,8 @@
     ///
     /// Add a new node map writer command for the writer.
     template <typename Writer, typename Map>
-    NodeSetWriter& writeMap(std::string name, const Map& map, 
-			     const Writer& writer = Writer()) {
+    NodeSetWriter& writeNodeMap(std::string name, const Map& map, 
+			    const Writer& writer = Writer()) {
       writers.push_back(
 	make_pair(name, new MapWriter<Item, Map, Writer>(map, writer)));
       return *this;
@@ -394,15 +395,15 @@
     WriterBase<Item>* idMap;
     bool forceIdMap;
    
-    const Graph& graph;   
+    typename SmartConstReference<Graph>::Type graph;   
     std::string id;
 
   };
 
   /// \ingroup io_group
-  /// \brief SectionWriter for writing a graph's edgeset.
+  /// \brief SectionWriter for writing a graph's edgesets.
   ///
-  /// The lemon format can store multiple graph edgesets with several maps.
+  /// 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.
   ///
@@ -413,7 +414,7 @@
   ///
   /// If the edgeset contains an \c "id" named map then it will be regarded
   /// as id map. This map should contain only unique values and when the 
-  /// \c writeId() member will be called with a edge it will write it's id.
+  /// \c writeId() member will be called with an edge it will write it's id.
   /// Otherwise if the \c _forceIdMap constructor parameter is true then
   /// the id map will be the id in the graph.
   ///
@@ -436,7 +437,7 @@
     /// Constructor for EdgeSetWriter. It creates the EdgeSetWriter and
     /// attach it into the given LemonWriter. It will write node ids by
     /// the \c _nodeIdWriter. If the \c _forceIdMap parameter is true 
-    /// then the writer will write own id map when the user does not give 
+    /// then the writer will write own id map if the user does not give 
     /// "id" named map.
     template <typename NodeIdWriter>
     EdgeSetWriter(LemonWriter& _writer, const Graph& _graph, 
@@ -464,21 +465,21 @@
 
   public:
 
-    /// \brief Add a new node map writer command for the writer.
+    /// \brief Add a new edge map writer command for the writer.
     ///
-    /// Add a new node map writer command for the writer.
+    /// Add a new edge map writer command for the writer.
     template <typename Map>
-    EdgeSetWriter& writeMap(std::string name, const Map& map) {
-      return writeMap<typename Traits::
+    EdgeSetWriter& writeEdgeMap(std::string name, const Map& map) {
+      return writeEdgeMap<typename Traits::
 	template Writer<typename Map::Value>, Map>(name, map);
     }
 
-    /// \brief Add a new node map writer command for the writer.
+    /// \brief Add a new edge map writer command for the writer.
     ///
-    /// Add a new node map writer command for the writer.
+    /// Add a new edge map writer command for the writer.
     template <typename Writer, typename Map>
-    EdgeSetWriter& writeMap(std::string name, const Map& map, 
-			     const Writer& writer = Writer()) {
+    EdgeSetWriter& writeEdgeMap(std::string name, const Map& map, 
+			    const Writer& writer = Writer()) {
       writers.push_back(
 	make_pair(name, new MapWriter<Item, Map, Writer>(map, writer)));
       return *this;
@@ -561,7 +562,203 @@
     WriterBase<Item>* idMap;
     bool forceIdMap;
    
-    const Graph& graph;   
+    typename SmartConstReference<Graph>::Type graph;   
+    std::string id;
+
+    std::auto_ptr<IdWriterBase<typename Graph::Node> > nodeIdWriter;
+  };
+
+  /// \ingroup io_group
+  /// \brief SectionWriter for writing a undirected edgeset.
+  ///
+  /// The lemon format can store multiple undirected edgesets with several 
+  /// maps. The undirected edgeset section's header line is \c \@undiredgeset 
+  /// \c undiredgeset_id, but the \c undiredgeset_id may be empty.
+  ///
+  /// The first line of the section contains the names of the maps separated
+  /// with white spaces. Each next lines describes an undirected edge in the 
+  /// edgeset. The line contains the two connected nodes' id and the mapped 
+  /// values for each undirected map.
+  ///
+  /// The section can handle the directed as a syntactical sugar. Two
+  /// undirected edge map describes one directed edge map. This two maps
+  /// are the forward map and the backward map and the names of this map
+  /// is near the same just with a prefix \c '+' or \c '-' character 
+  /// difference.
+  ///
+  /// If the edgeset contains an \c "id" named map then it will be regarded
+  /// as id map. This map should contain only unique values and when the 
+  /// \c writeId() member will be called with an undirected edge it will 
+  /// write it's id. Otherwise if the \c _forceIdMap constructor parameter
+  /// is true then the id map will be the id in the graph.
+  ///
+  /// The undirected edgeset writer needs a node id writer to identify 
+  /// which nodes have to be connected. If a NodeSetWriter can write the 
+  /// nodes' id, it will be able to use with this class.
+  ///
+  /// \relates LemonWriter
+  template <typename _Graph, typename _Traits = DefaultWriterTraits>
+  class UndirEdgeSetWriter : public CommonSectionWriterBase {
+    typedef CommonSectionWriterBase Parent;
+  public:
+
+    typedef _Graph Graph;
+    typedef _Traits Traits;
+    typedef typename Graph::UndirEdge Item;
+
+    /// \brief Constructor.
+    ///
+    /// Constructor for UndirEdgeSetWriter. It creates the UndirEdgeSetWriter
+    /// and attach it into the given LemonWriter. It will write node ids by
+    /// the \c _nodeIdWriter. If the \c _forceIdMap parameter is true 
+    /// then the writer will write own id map if the user does not give 
+    /// "id" named map.
+    template <typename NodeIdWriter>
+    UndirEdgeSetWriter(LemonWriter& _writer, const Graph& _graph, 
+		       const NodeIdWriter& _nodeIdWriter, 
+		       const std::string& _id = std::string(),
+		       bool _forceIdMap = true)
+      : Parent(_writer), idMap(0), forceIdMap(_forceIdMap),
+	graph(_graph), id(_id),
+	nodeIdWriter(new IdWriter<typename Graph::Node, NodeIdWriter>
+		     (_nodeIdWriter)) {} 
+
+    /// \brief Destructor.
+    ///
+    /// Destructor for UndirEdgeSetWriter.
+    virtual ~UndirEdgeSetWriter() {
+      typename MapWriters::iterator it;
+      for (it = writers.begin(); it != writers.end(); ++it) {
+	delete it->second;
+      }
+    }
+
+  private:
+    UndirEdgeSetWriter(const UndirEdgeSetWriter&);
+    void operator=(const UndirEdgeSetWriter&);
+
+  public:
+
+    /// \brief Add a new undirected edge map writer command for the writer.
+    ///
+    /// Add a new undirected map writer command for the writer.
+    template <typename Map>
+    UndirEdgeSetWriter& writeUndirEdgeMap(std::string name, const Map& map) {
+      return writeUndirEdgeMap<typename Traits::
+	template Writer<typename Map::Value>, Map>(name, map);
+    }
+
+    /// \brief Add a new undirected map writer command for the writer.
+    ///
+    /// Add a new undirected map writer command for the writer.
+    template <typename Writer, typename Map>
+    UndirEdgeSetWriter& writeUndirEdgeMap(std::string name, const Map& map, 
+					  const Writer& writer = Writer()) {
+      writers.push_back(
+	make_pair(name, new MapWriter<Item, Map, Writer>(map, writer)));
+      return *this;
+    }
+
+    /// \brief Add a new directed edge map writer command for the writer.
+    ///
+    /// Add a new directed map writer command for the writer.
+    template <typename Map>
+    UndirEdgeSetWriter& writeEdgeMap(std::string name, const Map& map) {
+      writeUndirEdgeMap("+" + name, composeMap(forwardMap(graph), map));
+      writeUndirEdgeMap("-" + name, composeMap(backwardMap(graph), map));
+      return *this;
+    }
+
+    /// \brief Add a new directed map writer command for the writer.
+    ///
+    /// Add a new directed map writer command for the writer.
+    template <typename Writer, typename Map>
+    UndirEdgeSetWriter& writeEdgeMap(std::string name, const Map& map, 
+				     const Writer& writer = Writer()) {
+      writeUndirEdge("+" + name, composeMap(forwardMap(graph), map), writer);
+      writeUndirEdge("-" + name, composeMap(forwardMap(graph), map), writer);
+      return *this;
+    }
+
+  protected:
+
+    /// \brief The header of the section.
+    ///
+    /// It gives back the header of the section.
+    virtual std::string header() {
+      return "@undiredgeset " + id;
+    }
+
+    /// \brief  Writer function of the section.
+    ///
+    /// Write the content of the section.
+    virtual void write(std::ostream& os) {
+      for (int i = 0; i < (int)writers.size(); ++i) {
+	if (writers[i].first == "id") {
+	  idMap = writers[i].second;
+	  forceIdMap = false;
+	  break;
+	}
+      }
+      os << "\t\t";
+      if (forceIdMap) {
+	os << "id\t";
+      }
+      for (int i = 0; i < (int)writers.size(); ++i) {
+	os << writers[i].first << '\t';
+      }
+      os << std::endl;
+      for (typename Graph::UndirEdgeIt it(graph); it != INVALID; ++it) {
+	nodeIdWriter->write(os, graph.source(it));
+	os << '\t';
+	nodeIdWriter->write(os, graph.target(it));
+	os << '\t';
+	if (forceIdMap) {
+	  os << graph.id(it) << '\t';
+	}
+	for (int i = 0; i < (int)writers.size(); ++i) {
+	  writers[i].second->write(os, it);
+	  os << '\t';
+	}
+	os << std::endl;
+      }
+    }
+
+  public:
+
+    /// \brief Returns true if the undirected edgeset can write the ids of 
+    /// the edges.
+    ///
+    /// Returns true if the undirected edgeset can write the ids of the 
+    /// undirected edges. It is possible only if an "id" named map was 
+    /// written or the \c _forceIdMap constructor parameter was true.
+    bool isIdWriter() const {
+      return forceIdMap || idMap != 0;
+    }
+
+    /// \brief Write the id of the given undirected edge.
+    ///
+    /// It writes the id of the given undirected edge. If there was written 
+    /// an "id" named map then it will write the map value belongs to the 
+    /// undirected edge. Otherwise if the \c forceId parameter was true it 
+    /// will write its id in the graph. 
+    void writeId(std::ostream& os, const Item& item) const {
+      if (forceIdMap) {
+	os << graph.id(item);
+      } else {
+	idMap->write(os, item);
+      }
+    } 
+
+  private:
+
+    typedef std::vector<std::pair<std::string, WriterBase<Item>*> > MapWriters;
+    MapWriters writers;
+
+    WriterBase<Item>* idMap;
+    bool forceIdMap;
+   
+    typename SmartConstReference<Graph>::Type graph;   
     std::string id;
 
     std::auto_ptr<IdWriterBase<typename Graph::Node> > nodeIdWriter;
@@ -617,7 +814,7 @@
 
     /// \brief Header checking function.
     ///
-    /// It gives back true when the header line start with \c @nodes,
+    /// It gives back true when the header line start with \c \@nodes,
     /// and the header line's id and the writer's id are the same.
     virtual std::string header() {
       return "@nodes " + id;
@@ -644,7 +841,7 @@
   };
 
   /// \ingroup io_group
-  /// \brief SectionWriter for writeing labeled edges.
+  /// \brief SectionWriter for writing labeled edges.
   ///
   /// The edges section's header line is \c \@edges \c edges_id, but the
   /// \c edges_id may be empty.
@@ -681,9 +878,9 @@
 
   public:
 
-    /// \brief Add an edge writer command for the NodeWriter.
+    /// \brief Add an edge writer command for the EdgeWriter.
     ///
-    /// Add an edge writer command for the NodeWriter.
+    /// Add an edge writer command for the EdgeWriter.
     void writeEdge(const std::string& name, const Item& item) {
       writers.push_back(make_pair(name, &item));
     }
@@ -692,7 +889,85 @@
 
     /// \brief Header checking function.
     ///
-    /// It gives back true when the header line start with \c @nodes,
+    /// It gives back true when the header line start with \c \@edges,
+    /// and the header line's id and the writer's id are the same.
+    virtual std::string header() {
+      return "@edges " + id;
+    }
+
+    /// \brief  Writer function of the section.
+    ///
+    /// Write the content of the section.
+    virtual void write(std::ostream& os) {
+      for (int i = 0; i < (int)writers.size(); ++i) {
+	os << writers[i].first << ' ';
+	idWriter->write(os, *(writers[i].second));
+	os << std::endl;
+      }
+    }
+    
+  private:
+
+    std::string id;
+
+    typedef std::vector<std::pair<std::string, const Item*> > ItemWriters;
+    ItemWriters writers;
+
+    std::auto_ptr<IdWriterBase<Item> > idWriter;
+  };
+
+  /// \ingroup io_group
+  /// \brief SectionWriter for writing labeled undirected edges.
+  ///
+  /// The undirected edges section's header line is \c \@undiredges 
+  /// \c undiredges_id, but the \c undiredges_id may be empty.
+  ///
+  /// Each line in the section contains the label of the undirected edge and 
+  /// then the undirected edge id. 
+  ///
+  /// \relates LemonWriter
+  template <typename _Graph>
+  class UndirEdgeWriter : public CommonSectionWriterBase {
+    typedef CommonSectionWriterBase Parent;
+    typedef _Graph Graph;
+    typedef typename Graph::UndirEdge Item;
+  public:
+    
+    /// \brief Constructor.
+    ///
+    /// Constructor for UndirEdgeWriter. It creates the UndirEdgeWriter and
+    /// attach it into the given LemonWriter. The given \c _IdWriter
+    /// will write the undirected edges' id what can be an undirected 
+    /// edgeset writer.
+    template <typename _IdWriter>
+    UndirEdgeWriter(LemonWriter& _writer, const _IdWriter& _idWriter, 
+	       const std::string& _id = std::string()) 
+      : Parent(_writer), id(_id), 
+	idWriter(new IdWriter<typename Graph::UndirEdge, _IdWriter>
+		 (_idWriter)) {} 
+
+    /// \brief Destructor.
+    ///
+    /// Destructor for UndirEdgeWriter.
+    virtual ~UndirEdgeWriter() {}
+  private:
+    UndirEdgeWriter(const UndirEdgeWriter&);
+    void operator=(const UndirEdgeWriter&);
+
+  public:
+
+    /// \brief Add an undirected edge writer command for the UndirEdgeWriter.
+    ///
+    /// Add an edge writer command for the UndirEdgeWriter.
+    void writeUndirEdge(const std::string& name, const Item& item) {
+      writers.push_back(make_pair(name, &item));
+    }
+
+  protected:
+
+    /// \brief Header checking function.
+    ///
+    /// It gives back true when the header line start with \c \@undiredges,
     /// and the header line's id and the writer's id are the same.
     virtual std::string header() {
       return "@edges " + id;



More information about the Lemon-commits mailing list