src/lemon/lemon_reader.h
changeset 1409 d2d1f8fa187b
parent 1408 892c29484414
child 1421 7a21e1414c38
     1.1 --- a/src/lemon/lemon_reader.h	Mon May 09 11:24:26 2005 +0000
     1.2 +++ b/src/lemon/lemon_reader.h	Wed May 11 11:50:13 2005 +0000
     1.3 @@ -30,16 +30,41 @@
     1.4  #include <memory>
     1.5  
     1.6  #include <lemon/error.h>
     1.7 -#include "item_reader.h"
     1.8 +#include <lemon/bits/item_reader.h>
     1.9  
    1.10  
    1.11  namespace lemon {
    1.12  
    1.13 -  /// \addtogroup io_group
    1.14 -  /// @{
    1.15 -
    1.16 +  /// \ingroup io_group
    1.17    /// \brief Lemon Format reader class.
    1.18    /// 
    1.19 +  /// The Lemon Format contains several sections. We do not want to
    1.20 +  /// determine what sections are in a lemon file we give only a framework
    1.21 +  /// to read a section oriented format.
    1.22 +  ///
    1.23 +  /// In the Lemon Format each section starts with a line contains a \c \@
    1.24 +  /// character on the first not white space position. This line is the
    1.25 +  /// header line of the section. Each next lines belong to this section
    1.26 +  /// while it does not starts with \c \@ character. This line can start a 
    1.27 +  /// new section or if it can close the file with the \c \@end line.
    1.28 +  /// The file format ignore the empty lines and it may contain comments
    1.29 +  /// started with a \c # character to the end of the line. 
    1.30 +  ///
    1.31 +  /// The framework provides an abstract LemonReader::SectionReader class
    1.32 +  /// what defines the interface of a SectionReader. The SectionReader
    1.33 +  /// has the \c header() member function what get a header line string and
    1.34 +  /// decides if it want to process the next section. Several SectionReaders
    1.35 +  /// can be attached to an LemonReader and the first attached what can
    1.36 +  /// process the section will be used. Its \c read() member will called
    1.37 +  /// with a stream contains the section. From this stream the empty lines
    1.38 +  /// and comments are filtered out.
    1.39 +  ///
    1.40 +  /// \relates GraphReader
    1.41 +  /// \relates NodeSetReader
    1.42 +  /// \relates EdgeSetReader
    1.43 +  /// \relates NodesReader
    1.44 +  /// \relates EdgesReader
    1.45 +  /// \relates AttributeReader
    1.46    class LemonReader {
    1.47    private:
    1.48      
    1.49 @@ -185,24 +210,55 @@
    1.50  
    1.51    public:
    1.52  
    1.53 +    /// \brief Abstract base class for reading a section.
    1.54 +    ///
    1.55 +    /// This class has an \c header() member function what get a 
    1.56 +    /// header line string and decides if it want to process the next 
    1.57 +    /// section. Several SectionReaders can be attached to an LemonReader 
    1.58 +    /// and the first attached what can process the section will be used. 
    1.59 +    /// Its \c read() member will called with a stream contains the section. 
    1.60 +    /// From this stream the empty lines and comments are filtered out.
    1.61      class SectionReader {
    1.62 -    public:
    1.63 -      /// \e
    1.64 +      friend class LemonReader;
    1.65 +    protected:
    1.66 +      /// \brief Constructor for SectionReader.
    1.67 +      ///
    1.68 +      /// Constructor for SectionReader. It attach this reader to
    1.69 +      /// the given LemonReader.
    1.70 +      SectionReader(LemonReader& reader) {
    1.71 +	reader.attach(*this);
    1.72 +      }
    1.73 +
    1.74 +      /// \brief Gives back true when the SectionReader can process 
    1.75 +      /// the section with the given header line.
    1.76 +      ///
    1.77 +      /// It gives back true when the SectionReader can process
    1.78 +      /// the section with the given header line.
    1.79        virtual bool header(const std::string& line) = 0;
    1.80 -      /// \e
    1.81 +
    1.82 +      /// \brief Reader function of the section.
    1.83 +      ///
    1.84 +      /// It reads the content of the section.
    1.85        virtual void read(std::istream& is) = 0;
    1.86      };
    1.87  
    1.88 -    /// \e
    1.89 +    /// \brief Constructor for LemonReader.
    1.90 +    ///
    1.91 +    /// Constructor for LemonReader which reads from the given stream.
    1.92      LemonReader(std::istream& _is) 
    1.93        : is(&_is), own_is(false) {}
    1.94  
    1.95 +    /// \brief Constructor for LemonReader.
    1.96 +    ///
    1.97 +    /// Constructor for LemonReader which reads from the given file.
    1.98      LemonReader(const std::string& filename) 
    1.99        : is(0), own_is(true) {
   1.100        is = new std::ifstream(filename.c_str());
   1.101      }
   1.102  
   1.103 -
   1.104 +    /// \brief Desctructor for LemonReader.
   1.105 +    ///
   1.106 +    /// Desctructor for LemonReader.
   1.107      ~LemonReader() {
   1.108        if (own_is) {
   1.109  	delete is;
   1.110 @@ -213,23 +269,14 @@
   1.111      LemonReader(const LemonReader&);
   1.112      void operator=(const LemonReader&);
   1.113  
   1.114 -  public:
   1.115 -    
   1.116 -    /// \e
   1.117      void attach(SectionReader& reader) {
   1.118        readers.push_back(&reader);
   1.119      }
   1.120  
   1.121 -    /// \e
   1.122 -    void detach(SectionReader& reader) {
   1.123 -      std::vector<SectionReader*>::iterator it = 
   1.124 -	std::find(readers.begin(), readers.end(), &reader);
   1.125 -      if (it != readers.end()) {
   1.126 -	readers.erase(it);
   1.127 -      }
   1.128 -    }
   1.129 -
   1.130 -    /// \e
   1.131 +  public:
   1.132 +    /// \brief Executes the LemonReader.
   1.133 +    /// 
   1.134 +    /// It executes the LemonReader.
   1.135      void run() {
   1.136        int line_num = 0;
   1.137        std::string line;
   1.138 @@ -264,10 +311,20 @@
   1.139  
   1.140    };
   1.141  
   1.142 +  /// \brief Helper class for implementing the common SectionReaders.
   1.143 +  ///
   1.144 +  /// Helper class for implementing the common SectionReaders.
   1.145 +  class CommonSectionReaderBase : public LemonReader::SectionReader {
   1.146 +    typedef LemonReader::SectionReader Parent;
   1.147 +  protected:
   1.148 +    
   1.149 +    /// \brief Constructor for CommonSectionReaderBase.
   1.150 +    ///
   1.151 +    /// Constructor for CommonSectionReaderBase. It attach this reader to
   1.152 +    /// the given LemonReader.
   1.153 +    CommonSectionReaderBase(LemonReader& _reader) 
   1.154 +      : Parent(_reader) {}
   1.155  
   1.156 -  /// \e
   1.157 -  class CommonSectionReaderBase : public LemonReader::SectionReader {
   1.158 -  protected:
   1.159      template <typename _Item>
   1.160      class ReaderBase;
   1.161      
   1.162 @@ -433,25 +490,25 @@
   1.163      };
   1.164  
   1.165      template <typename _Item>
   1.166 -    class ResolverReaderBase {
   1.167 +    class IdReaderBase {
   1.168      public:
   1.169        typedef _Item Item;
   1.170 -      virtual Item resolve(std::istream& is) const = 0;
   1.171 +      virtual Item read(std::istream& is) const = 0;
   1.172      };
   1.173  
   1.174 -    template <typename _Item, typename _Resolver>
   1.175 -    class ResolverReader : public ResolverReaderBase<_Item> {
   1.176 +    template <typename _Item, typename _BoxedIdReader>
   1.177 +    class IdReader : public IdReaderBase<_Item> {
   1.178      public:
   1.179        typedef _Item Item;
   1.180 -      typedef _Resolver Resolver;
   1.181 +      typedef _BoxedIdReader BoxedIdReader;
   1.182 +      
   1.183 +      const BoxedIdReader& boxedIdReader;
   1.184  
   1.185 -      const Resolver& resolver;
   1.186 +      IdReader(const BoxedIdReader& _boxedIdReader) 
   1.187 +	: boxedIdReader(_boxedIdReader) {}
   1.188  
   1.189 -      ResolverReader(const Resolver& _resolver) 
   1.190 -	: resolver(_resolver) {}
   1.191 -
   1.192 -      virtual Item resolve(std::istream& is) const {
   1.193 -	return resolver.resolve(is);
   1.194 +      virtual Item read(std::istream& is) const {
   1.195 +	return boxedIdReader.readId(is);
   1.196        }
   1.197      };
   1.198  
   1.199 @@ -479,7 +536,23 @@
   1.200      
   1.201    };
   1.202  
   1.203 -
   1.204 +  /// \ingroup io_group
   1.205 +  /// \brief SectionReader for reading a graph's nodeset.
   1.206 +  ///
   1.207 +  /// The lemon format can store multiple graph nodesets with several maps.
   1.208 +  /// The nodeset section's header line is \c \@nodeset \c nodeset_id, but the
   1.209 +  /// \c nodeset_id may be empty.
   1.210 +  ///
   1.211 +  /// The first line of the section contains the names of the maps separated
   1.212 +  /// with white spaces. Each next lines describes a node in the nodeset, and
   1.213 +  /// contains the mapped values for each map.
   1.214 +  ///
   1.215 +  /// If the nodeset contains an \c "id" named map then it will be regarded
   1.216 +  /// as id map. This map should contain only unique values and when the 
   1.217 +  /// \c readId() member will read a value from the given stream it will
   1.218 +  /// give back that node which is mapped to this value.
   1.219 +  ///
   1.220 +  /// \relates LemonReader
   1.221    template <typename _Graph, typename _Traits = DefaultReaderTraits>
   1.222    class NodeSetReader : public CommonSectionReaderBase {
   1.223      typedef CommonSectionReaderBase Parent;
   1.224 @@ -490,13 +563,21 @@
   1.225      typedef typename Graph::Node Item;
   1.226      typedef typename Traits::Skipper DefaultSkipper;
   1.227  
   1.228 +    /// \brief Constructor.
   1.229 +    ///
   1.230 +    /// Constructor for NodeSetReader. It creates the NodeSetReader and
   1.231 +    /// attach it into the given LemonReader. The nodeset reader will
   1.232 +    /// add the readed nodes to the given Graph. The reader will read
   1.233 +    /// the section when the \c section_id and the \c _id are the same. 
   1.234      NodeSetReader(LemonReader& _reader, Graph& _graph, 
   1.235  		  const std::string& _id = std::string(),
   1.236 -		  const DefaultSkipper& _defreader = DefaultSkipper()) 
   1.237 -      : graph(_graph), id(_id), skipper(_defreader) {
   1.238 -      _reader.attach(*this);
   1.239 -    } 
   1.240 +		  const DefaultSkipper& _skipper = DefaultSkipper()) 
   1.241 +      : Parent(_reader), graph(_graph), id(_id), skipper(_skipper) {} 
   1.242  
   1.243 +
   1.244 +    /// \brief Destructor.
   1.245 +    ///
   1.246 +    /// Destructor for NodeSetReader.
   1.247      virtual ~NodeSetReader() {
   1.248        for (typename MapReaders::iterator it = readers.begin(); 
   1.249  	   it != readers.end(); ++it) {
   1.250 @@ -550,7 +631,13 @@
   1.251        return *this;
   1.252      }
   1.253  
   1.254 -    /// \e
   1.255 +  protected:
   1.256 +
   1.257 +    /// \brief Gives back true when the SectionReader can process 
   1.258 +    /// the section with the given header line.
   1.259 +    ///
   1.260 +    /// It gives back true when the header line starts with \c @nodeset,
   1.261 +    /// and the header line's id and the nodeset's id are the same.
   1.262      virtual bool header(const std::string& line) {
   1.263        std::istringstream ls(line);
   1.264        std::string command;
   1.265 @@ -559,7 +646,9 @@
   1.266        return command == "@nodeset" && name == id;
   1.267      }
   1.268  
   1.269 -    /// \e
   1.270 +    /// \brief Reader function of the section.
   1.271 +    ///
   1.272 +    /// It reads the content of the section.
   1.273      virtual void read(std::istream& is) {
   1.274        std::vector<ReaderBase<Item>* > index;
   1.275        std::string line;
   1.276 @@ -587,11 +676,21 @@
   1.277        }
   1.278      }
   1.279  
   1.280 -    bool isResolver() const {
   1.281 +  public:
   1.282 +
   1.283 +    /// \brief Returns true if the nodeset can give back the node by its id.
   1.284 +    ///
   1.285 +    /// Returns true if the nodeset can give back the node by its id.
   1.286 +    /// It is possible only if an "id" named map was read.
   1.287 +    bool isIdReader() const {
   1.288        return inverter.get() != 0;
   1.289      }
   1.290  
   1.291 -    typename Graph::Node resolve(std::istream& is) const {
   1.292 +    /// \brief Gives back the node by its id.
   1.293 +    ///
   1.294 +    /// It reads an id from the stream and gives back which node belongs to
   1.295 +    /// it. It is possible only if there was read an "id" named map.
   1.296 +    typename Graph::Node readId(std::istream& is) const {
   1.297        return inverter->read(is);
   1.298      } 
   1.299  
   1.300 @@ -607,9 +706,27 @@
   1.301      std::auto_ptr<InverterBase<Item> > inverter;
   1.302    };
   1.303  
   1.304 -
   1.305 - 
   1.306 -  /// \e
   1.307 +  /// \ingroup io_group
   1.308 +  /// \brief SectionReader for reading a graph's edgeset.
   1.309 +  ///
   1.310 +  /// The lemon format can store multiple graph edgesets with several maps.
   1.311 +  /// The edgeset section's header line is \c \@edgeset \c edgeset_id, but the
   1.312 +  /// \c edgeset_id may be empty.
   1.313 +  ///
   1.314 +  /// The first line of the section contains the names of the maps separated
   1.315 +  /// with white spaces. Each next lines describes a node in the nodeset. The
   1.316 +  /// line contains the two nodes' id and the mapped values for each map.
   1.317 +  ///
   1.318 +  /// If the edgeset contains an \c "id" named map then it will be regarded
   1.319 +  /// as id map. This map should contain only unique values and when the 
   1.320 +  /// \c readId() member will read a value from the given stream it will
   1.321 +  /// give back that edge which is mapped to this value.
   1.322 +  ///
   1.323 +  /// The edgeset reader needs a node id reader to identify which nodes
   1.324 +  /// have to be connected. If a NodeSetReader reads an "id" named map,
   1.325 +  /// it will be able to resolve the nodes by ids.
   1.326 +  ///
   1.327 +  /// \relates LemonReader
   1.328    template <typename _Graph, typename _Traits = DefaultReaderTraits>
   1.329    class EdgeSetReader : public CommonSectionReaderBase {
   1.330      typedef CommonSectionReaderBase Parent;
   1.331 @@ -620,17 +737,26 @@
   1.332      typedef typename Graph::Edge Item;
   1.333      typedef typename Traits::Skipper DefaultSkipper;
   1.334  
   1.335 -    template <typename Resolver>
   1.336 +    /// \brief Constructor.
   1.337 +    ///
   1.338 +    /// Constructor for EdgeSetReader. It creates the EdgeSetReader and
   1.339 +    /// attach it into the given LemonReader. The edgeset reader will
   1.340 +    /// add the readed edges to the given Graph. It will use the given
   1.341 +    /// node id reader to read the source and target nodes of the edges.
   1.342 +    /// The reader will read the section only if the \c _id and the 
   1.343 +    /// \c edgset_id are the same. 
   1.344 +    template <typename NodeIdReader>
   1.345      EdgeSetReader(LemonReader& _reader, Graph& _graph, 
   1.346 -		  const Resolver& _nodeResolver, 
   1.347 +		  const NodeIdReader& _nodeIdReader, 
   1.348  		  const std::string& _id = std::string(),
   1.349 -		  const DefaultSkipper& _defreader = DefaultSkipper()) 
   1.350 -      : graph(_graph), id(_id), skipper(_defreader),
   1.351 -      nodeResolver(new ResolverReader<typename Graph::Node, Resolver>
   1.352 -		   (_nodeResolver)) {
   1.353 -      _reader.attach(*this);
   1.354 -    } 
   1.355 +		  const DefaultSkipper& _skipper = DefaultSkipper()) 
   1.356 +      : Parent(_reader), graph(_graph), id(_id), skipper(_skipper),
   1.357 +	nodeIdReader(new IdReader<typename Graph::Node, NodeIdReader>
   1.358 +		     (_nodeIdReader)) {} 
   1.359  
   1.360 +    /// \brief Destructor.
   1.361 +    ///
   1.362 +    /// Destructor for EdgeSetReader.
   1.363      virtual ~EdgeSetReader() {
   1.364        for (typename MapReaders::iterator it = readers.begin(); 
   1.365  	   it != readers.end(); ++it) {
   1.366 @@ -644,18 +770,18 @@
   1.367  
   1.368    public:
   1.369  
   1.370 -    /// \brief Add a new node map reader command for the reader.
   1.371 +    /// \brief Add a new edge map reader command for the reader.
   1.372      ///
   1.373 -    /// Add a new node map reader command for the reader.
   1.374 +    /// Add a new edge map reader command for the reader.
   1.375      template <typename Map>
   1.376      EdgeSetReader& readMap(std::string name, Map& map) {
   1.377        return readMap<typename Traits::
   1.378  	template Reader<typename Map::Value>, Map>(name, map);
   1.379      }
   1.380  
   1.381 -    /// \brief Add a new node map reader command for the reader.
   1.382 +    /// \brief Add a new edge map reader command for the reader.
   1.383      ///
   1.384 -    /// Add a new node map reader command for the reader.
   1.385 +    /// Add a new edge map reader command for the reader.
   1.386      template <typename Reader, typename Map>
   1.387      EdgeSetReader& readMap(std::string name, Map& map, 
   1.388  			     const Reader& reader = Reader()) {
   1.389 @@ -669,9 +795,9 @@
   1.390        return *this;
   1.391      }
   1.392  
   1.393 -    /// \brief Add a new node map skipper command for the reader.
   1.394 +    /// \brief Add a new edge map skipper command for the reader.
   1.395      ///
   1.396 -    /// Add a new node map skipper command for the reader.
   1.397 +    /// Add a new edge map skipper command for the reader.
   1.398      template <typename Reader>
   1.399      EdgeSetReader& skipMap(std::string name, 
   1.400  			   const Reader& reader = Reader()) {
   1.401 @@ -684,7 +810,13 @@
   1.402        return *this;
   1.403      }
   1.404  
   1.405 -    /// \e
   1.406 +  protected:
   1.407 +
   1.408 +    /// \brief Gives back true when the SectionReader can process 
   1.409 +    /// the section with the given header line.
   1.410 +    ///
   1.411 +    /// It gives back true when the header line starts with \c @edgeset,
   1.412 +    /// and the header line's id and the edgeset's id are the same.
   1.413      virtual bool header(const std::string& line) {
   1.414        std::istringstream ls(line);
   1.415        std::string command;
   1.416 @@ -693,7 +825,9 @@
   1.417        return command == "@edgeset" && name == id;
   1.418      }
   1.419  
   1.420 -    /// \e
   1.421 +    /// \brief Reader function of the section.
   1.422 +    ///
   1.423 +    /// It reads the content of the section.
   1.424      virtual void read(std::istream& is) {
   1.425        std::vector<ReaderBase<Item>* > index;
   1.426        std::string line;
   1.427 @@ -714,8 +848,8 @@
   1.428        }
   1.429        while (getline(is, line)) {	
   1.430  	std::istringstream ls(line);
   1.431 -	typename Graph::Node from = nodeResolver->resolve(ls);
   1.432 -	typename Graph::Node to = nodeResolver->resolve(ls);
   1.433 +	typename Graph::Node from = nodeIdReader->read(ls);
   1.434 +	typename Graph::Node to = nodeIdReader->read(ls);
   1.435  	typename Graph::Edge edge = graph.addEdge(from, to);
   1.436  	for (int i = 0; i < (int)index.size(); ++i) {
   1.437  	  index[i]->read(ls, edge);
   1.438 @@ -723,11 +857,21 @@
   1.439        }
   1.440      }
   1.441  
   1.442 -    bool isResolver() const {
   1.443 +  public:
   1.444 +
   1.445 +    /// \brief Returns true if the edgeset can give back the edge by its id.
   1.446 +    ///
   1.447 +    /// Returns true if the edgeset can give back the edge by its id.
   1.448 +    /// It is possible only if an "id" named map was read.
   1.449 +    bool isIdReader() const {
   1.450        return inverter.get() != 0;
   1.451      }
   1.452  
   1.453 -    typename Graph::Edge resolve(std::istream& is) {
   1.454 +    /// \brief Gives back the edge by its id.
   1.455 +    ///
   1.456 +    /// It reads an id from the stream and gives back which edge belongs to
   1.457 +    /// it. It is possible only if there was read an "id" named map.
   1.458 +    typename Graph::Edge readId(std::istream& is) const {
   1.459        return inverter->read(is);
   1.460      } 
   1.461  
   1.462 @@ -741,23 +885,220 @@
   1.463      SkipReader<Item, DefaultSkipper> skipper;
   1.464  
   1.465      std::auto_ptr<InverterBase<Item> > inverter;
   1.466 -    std::auto_ptr<ResolverReaderBase<typename Graph::Node> > nodeResolver;
   1.467 +    std::auto_ptr<IdReaderBase<typename Graph::Node> > nodeIdReader;
   1.468    };
   1.469  
   1.470 +  /// \ingroup io_group
   1.471 +  /// \brief SectionReader for reading labeled nodes.
   1.472 +  ///
   1.473 +  /// The nodes section's header line is \c \@nodes \c nodes_id, but the
   1.474 +  /// \c nodes_id may be empty.
   1.475 +  ///
   1.476 +  /// Each line in the section contains the name of the node 
   1.477 +  /// and then the node id. 
   1.478 +  ///
   1.479 +  /// \relates LemonReader
   1.480 +  template <typename _Graph>
   1.481 +  class NodeReader : public CommonSectionReaderBase {
   1.482 +    typedef CommonSectionReaderBase Parent;
   1.483 +    typedef _Graph Graph;
   1.484 +    typedef typename Graph::Node Item;
   1.485 +  public:
   1.486 +    
   1.487 +    /// \brief Constructor.
   1.488 +    ///
   1.489 +    /// Constructor for NodeReader. It creates the NodeReader and
   1.490 +    /// attach it into the given LemonReader. It will use the given
   1.491 +    /// node id reader to give back the nodes. The reader will read the 
   1.492 +    /// section only if the \c _id and the \c nodes_id are the same. 
   1.493 +    template <typename _IdReader>
   1.494 +    NodeReader(LemonReader& _reader, const _IdReader& _idReader, 
   1.495 +	       const std::string& _id = std::string()) 
   1.496 +      : Parent(_reader), id(_id), 
   1.497 +	idReader(new IdReader<typename Graph::Node, _IdReader>(_idReader)) {} 
   1.498  
   1.499 -  /// \e
   1.500 +    /// \brief Destructor.
   1.501 +    ///
   1.502 +    /// Destructor for NodeReader.
   1.503 +    virtual ~NodeReader() {}
   1.504 +
   1.505 +  private:
   1.506 +    NodeReader(const NodeReader&);
   1.507 +    void operator=(const NodeReader&);
   1.508 +
   1.509 +  public:
   1.510 +
   1.511 +    /// \brief Add a node reader command for the NodeReader.
   1.512 +    ///
   1.513 +    /// Add a node reader command for the NodeReader.
   1.514 +    void readNode(const std::string& name, Item& item) {
   1.515 +      if (readers.find(name) != readers.end()) {
   1.516 +	ErrorMessage msg;
   1.517 +	msg << "Multiple read rule for node: " << name;
   1.518 +	throw IOParameterError(msg.message());
   1.519 +      }
   1.520 +      readers.insert(make_pair(name, &item));
   1.521 +    }
   1.522 +
   1.523 +  protected:
   1.524 +
   1.525 +    /// \brief Gives back true when the SectionReader can process 
   1.526 +    /// the section with the given header line.
   1.527 +    ///
   1.528 +    /// It gives back true when the header line start with \c @nodes,
   1.529 +    /// and the header line's id and the reader's id are the same.
   1.530 +    virtual bool header(const std::string& line) {
   1.531 +      std::istringstream ls(line);
   1.532 +      std::string command;
   1.533 +      std::string name;
   1.534 +      ls >> command >> name;
   1.535 +      return command == "@nodes" && name == id;
   1.536 +    }
   1.537 +
   1.538 +    /// \brief Reader function of the section.
   1.539 +    ///
   1.540 +    /// It reads the content of the section.
   1.541 +    virtual void read(std::istream& is) {
   1.542 +      std::string line;
   1.543 +      while (getline(is, line)) {
   1.544 +	std::istringstream ls(line);
   1.545 +	std::string id;
   1.546 +	ls >> id;
   1.547 +	typename ItemReaders::iterator it = readers.find(id);
   1.548 +	if (it != readers.end()) {
   1.549 +	  *(it->second) = idReader->read(ls); 
   1.550 +	}	
   1.551 +      }
   1.552 +    }
   1.553 +    
   1.554 +  private:
   1.555 +
   1.556 +    std::string id;
   1.557 +
   1.558 +    typedef std::map<std::string, Item*> ItemReaders;
   1.559 +    ItemReaders readers;
   1.560 +    std::auto_ptr<IdReaderBase<Item> > idReader;
   1.561 +  };
   1.562 +
   1.563 +  /// \ingroup io_group
   1.564 +  /// \brief SectionReader for reading labeled edges.
   1.565 +  ///
   1.566 +  /// The edges section's header line is \c \@edges \c edges_id, but the
   1.567 +  /// \c edges_id may be empty.
   1.568 +  ///
   1.569 +  /// Each line in the section contains the name of the edge 
   1.570 +  /// and then the edge id. 
   1.571 +  ///
   1.572 +  /// \relates LemonReader
   1.573 +  template <typename _Graph>
   1.574 +  class EdgeReader : public CommonSectionReaderBase {
   1.575 +    typedef CommonSectionReaderBase Parent;
   1.576 +    typedef _Graph Graph;
   1.577 +    typedef typename Graph::Edge Item;
   1.578 +  public:
   1.579 +    
   1.580 +    /// \brief Constructor.
   1.581 +    ///
   1.582 +    /// Constructor for EdgeReader. It creates the EdgeReader and
   1.583 +    /// attach it into the given LemonReader. It will use the given
   1.584 +    /// edge id reader to give back the edges. The reader will read the 
   1.585 +    /// section only if the \c _id and the \c nodes_id are the same. 
   1.586 +    template <typename _IdReader>
   1.587 +    EdgeReader(LemonReader& _reader, const _IdReader& _idReader, 
   1.588 +	       const std::string& _id = std::string()) 
   1.589 +      : Parent(_reader), id(_id), 
   1.590 +	idReader(new IdReader<typename Graph::Edge, _IdReader>(_idReader)) {} 
   1.591 +
   1.592 +    /// \brief Destructor.
   1.593 +    ///
   1.594 +    /// Destructor for EdgeReader.
   1.595 +    virtual ~EdgeReader() {}
   1.596 +  private:
   1.597 +    EdgeReader(const EdgeReader&);
   1.598 +    void operator=(const EdgeReader&);
   1.599 +
   1.600 +  public:
   1.601 +
   1.602 +    /// \brief Add an edge reader command for the EdgeReader.
   1.603 +    ///
   1.604 +    /// Add an edge reader command for the EdgeReader.
   1.605 +    void readEdge(const std::string& name, Item& item) {
   1.606 +      if (readers.find(name) != readers.end()) {
   1.607 +	ErrorMessage msg;
   1.608 +	msg << "Multiple read rule for edge: " << name;
   1.609 +	throw IOParameterError(msg.message());
   1.610 +      }
   1.611 +      readers.insert(make_pair(name, &item));
   1.612 +    }
   1.613 +
   1.614 +  protected:
   1.615 +
   1.616 +    /// \brief Gives back true when the SectionReader can process 
   1.617 +    /// the section with the given header line.
   1.618 +    ///
   1.619 +    /// It gives back true when the header line start with \c @edges,
   1.620 +    /// and the header line's id and the reader's id are the same.
   1.621 +    virtual bool header(const std::string& line) {
   1.622 +      std::istringstream ls(line);
   1.623 +      std::string command;
   1.624 +      std::string name;
   1.625 +      ls >> command >> name;
   1.626 +      return command == "@edges" && name == id;
   1.627 +    }
   1.628 +
   1.629 +    /// \brief Reader function of the section.
   1.630 +    ///
   1.631 +    /// It reads the content of the section.
   1.632 +    virtual void read(std::istream& is) {
   1.633 +      std::string line;
   1.634 +      while (getline(is, line)) {
   1.635 +	std::istringstream ls(line);
   1.636 +	std::string id;
   1.637 +	ls >> id;
   1.638 +	typename ItemReaders::iterator it = readers.find(id);
   1.639 +	if (it != readers.end()) {
   1.640 +	  *(it->second) = idReader->read(ls); 
   1.641 +	}	
   1.642 +      }
   1.643 +    }
   1.644 +    
   1.645 +  private:
   1.646 +
   1.647 +    std::string id;
   1.648 +
   1.649 +    typedef std::map<std::string, Item*> ItemReaders;
   1.650 +    ItemReaders readers;
   1.651 +    std::auto_ptr<IdReaderBase<Item> > idReader;
   1.652 +  };
   1.653 +
   1.654 +  /// \ingroup io_group
   1.655 +  /// \brief SectionReader for attributes.
   1.656 +  ///
   1.657 +  /// The lemon format can store multiple attribute set. Each set has
   1.658 +  /// the header line \c \@attributes \c attributeset_id, but the 
   1.659 +  /// attributeset_id may be empty.
   1.660 +  ///
   1.661 +  /// The attributeset section contains several lines. Each of them starts
   1.662 +  /// with an attribute and then a the value for the id.
   1.663 +  ///
   1.664 +  /// \relates LemonReader
   1.665    template <typename _Traits = DefaultReaderTraits>
   1.666    class AttributeReader : public CommonSectionReaderBase {
   1.667      typedef CommonSectionReaderBase Parent;
   1.668      typedef _Traits Traits; 
   1.669    public:
   1.670 -    /// \e
   1.671 +    /// \brief Constructor.
   1.672 +    ///
   1.673 +    /// Constructor for AttributeReader. It creates the AttributeReader and
   1.674 +    /// attach it into the given LemonReader. The reader process a section
   1.675 +    /// only if the \c section_id and the \c _id are the same.
   1.676      AttributeReader(LemonReader& _reader, 
   1.677 -		    const std::string& _id = std::string()) : id(_id) {
   1.678 -      _reader.attach(*this);
   1.679 -    }
   1.680 +		    const std::string& _id = std::string()) 
   1.681 +      : Parent(_reader), id(_id) {}
   1.682  
   1.683 -    /// \e
   1.684 +    /// \brief Destructor.
   1.685 +    ///
   1.686 +    /// Destructor for AttributeReader.
   1.687      virtual ~AttributeReader() {
   1.688        for (typename Readers::iterator it = readers.begin(); 
   1.689  	   it != readers.end(); ++it) {
   1.690 @@ -770,14 +1111,18 @@
   1.691      void operator=(AttributeReader&);
   1.692  
   1.693    public:
   1.694 -    /// \e
   1.695 +    /// \brief Add an attribute reader command for the reader.
   1.696 +    ///
   1.697 +    /// Add an attribute reader command for the reader.
   1.698      template <typename Value>
   1.699      AttributeReader& readAttribute(const std::string& id, Value& value) {
   1.700        return readAttribute<typename Traits::template Reader<Value> >
   1.701  	(id, value);
   1.702      }
   1.703  
   1.704 -    /// \e
   1.705 +    /// \brief Add an attribute reader command for the reader.
   1.706 +    ///
   1.707 +    /// Add an attribute reader command for the reader.
   1.708      template <typename Reader, typename Value>
   1.709      AttributeReader& readAttribute(const std::string& name, Value& value,
   1.710  				   const Reader& reader = Reader()) {
   1.711 @@ -791,7 +1136,13 @@
   1.712        return *this;
   1.713      }
   1.714  
   1.715 -    /// \e
   1.716 +  protected:
   1.717 +
   1.718 +    /// \brief Gives back true when the SectionReader can process 
   1.719 +    /// the section with the given header line.
   1.720 +    ///
   1.721 +    /// It gives back true when the header line start with \c @attributes,
   1.722 +    /// and the header line's id and the attributeset's id are the same.
   1.723      bool header(const std::string& line) {
   1.724        std::istringstream ls(line);
   1.725        std::string command;
   1.726 @@ -800,7 +1151,9 @@
   1.727        return command == "@attributes" && name == id;
   1.728      }
   1.729  
   1.730 -    /// \e
   1.731 +    /// \brief Reader function of the section.
   1.732 +    ///
   1.733 +    /// It reads the content of the section.
   1.734      void read(std::istream& is) {
   1.735        std::string line;
   1.736        while (getline(is, line)) {
   1.737 @@ -818,160 +1171,9 @@
   1.738      std::string id;
   1.739  
   1.740      typedef std::map<std::string, ValueReaderBase*> Readers;
   1.741 -    Readers readers;
   1.742 -  
   1.743 +    Readers readers;  
   1.744    };
   1.745  
   1.746 -  template <typename _Graph>
   1.747 -  class NodeReader : public CommonSectionReaderBase {
   1.748 -    typedef CommonSectionReaderBase Parent;
   1.749 -    typedef _Graph Graph;
   1.750 -    typedef typename Graph::Node Item;
   1.751 -  public:
   1.752 -    
   1.753 -    template <typename Resolver>
   1.754 -    NodeReader(LemonReader& _reader, const Resolver& _resolver, 
   1.755 -	       const std::string& _id = std::string()) 
   1.756 -      : id(_id), resolver(new ResolverReader<typename Graph::Node, Resolver>
   1.757 -		     (_resolver)) {
   1.758 -      _reader.attach(*this);
   1.759 -    } 
   1.760  
   1.761 -    virtual ~NodeReader() {}
   1.762 -
   1.763 -  private:
   1.764 -    NodeReader(const NodeReader&);
   1.765 -    void operator=(const NodeReader&);
   1.766 -
   1.767 -  public:
   1.768 -
   1.769 -    void readNode(const std::string& name, Item& item) {
   1.770 -      if (readers.find(name) != readers.end()) {
   1.771 -	ErrorMessage msg;
   1.772 -	msg << "Multiple read rule for node: " << name;
   1.773 -	throw IOParameterError(msg.message());
   1.774 -      }
   1.775 -      readers.insert(make_pair(name, &item));
   1.776 -    }
   1.777 -
   1.778 -    virtual bool header(const std::string& line) {
   1.779 -      std::istringstream ls(line);
   1.780 -      std::string command;
   1.781 -      std::string name;
   1.782 -      ls >> command >> name;
   1.783 -      return command == "@nodes" && name == id;
   1.784 -    }
   1.785 -
   1.786 -    virtual void read(std::istream& is) {
   1.787 -      std::string line;
   1.788 -      while (getline(is, line)) {
   1.789 -	std::istringstream ls(line);
   1.790 -	std::string id;
   1.791 -	ls >> id;
   1.792 -	typename ItemReaders::iterator it = readers.find(id);
   1.793 -	if (it != readers.end()) {
   1.794 -	  *(it->second) = resolver->resolve(ls); 
   1.795 -	}	
   1.796 -      }
   1.797 -    }
   1.798 -    
   1.799 -  private:
   1.800 -
   1.801 -    std::string id;
   1.802 -
   1.803 -    typedef std::map<std::string, Item*> ItemReaders;
   1.804 -    ItemReaders readers;
   1.805 -    std::auto_ptr<ResolverReaderBase<Item> > resolver;
   1.806 -  };
   1.807 -
   1.808 -  template <typename _Graph>
   1.809 -  class EdgeReader : public CommonSectionReaderBase {
   1.810 -    typedef CommonSectionReaderBase Parent;
   1.811 -    typedef _Graph Graph;
   1.812 -    typedef typename Graph::Edge Item;
   1.813 -  public:
   1.814 -    
   1.815 -    template <typename Resolver>
   1.816 -    EdgeReader(LemonReader& _reader, const Resolver& _resolver, 
   1.817 -	       const std::string& _id = std::string()) 
   1.818 -      : id(_id), resolver(new ResolverReader<typename Graph::Node, Resolver>
   1.819 -		     (_resolver)) {
   1.820 -      _reader.attach(*this);
   1.821 -    } 
   1.822 -
   1.823 -    virtual ~EdgeReader() {}
   1.824 -  private:
   1.825 -    EdgeReader(const EdgeReader&);
   1.826 -    void operator=(const EdgeReader&);
   1.827 -
   1.828 -  public:
   1.829 -
   1.830 -    void readEdge(const std::string& name, Item& item) {
   1.831 -      if (readers.find(name) != readers.end()) {
   1.832 -	ErrorMessage msg;
   1.833 -	msg << "Multiple read rule for edge: " << name;
   1.834 -	throw IOParameterError(msg.message());
   1.835 -      }
   1.836 -      readers.insert(make_pair(name, &item));
   1.837 -    }
   1.838 -
   1.839 -
   1.840 -    virtual bool header(const std::string& line) {
   1.841 -      std::istringstream ls(line);
   1.842 -      std::string command;
   1.843 -      std::string name;
   1.844 -      ls >> command >> name;
   1.845 -      return command == "@nodes" && name == id;
   1.846 -    }
   1.847 -
   1.848 -    virtual void read(std::istream& is) {
   1.849 -      std::string line;
   1.850 -      while (getline(is, line)) {
   1.851 -	std::istringstream ls(line);
   1.852 -	std::string id;
   1.853 -	ls >> id;
   1.854 -	typename ItemReaders::iterator it = readers.find(id);
   1.855 -	if (it != readers.end()) {
   1.856 -	  *(it->second) = resolver->resolve(ls); 
   1.857 -	}	
   1.858 -      }
   1.859 -    }
   1.860 -    
   1.861 -  private:
   1.862 -
   1.863 -    std::string id;
   1.864 -
   1.865 -    typedef std::map<std::string, Item*> ItemReaders;
   1.866 -    ItemReaders readers;
   1.867 -    std::auto_ptr<ResolverReaderBase<Item> > resolver;
   1.868 -  };
   1.869 -
   1.870 -  /// \e
   1.871 -  class PrintReader : public LemonReader::SectionReader {
   1.872 -    typedef LemonReader::SectionReader Parent;
   1.873 -  public:
   1.874 -
   1.875 -    /// \e
   1.876 -    PrintReader(LemonReader& reader) {
   1.877 -      reader.attach(*this);
   1.878 -    }
   1.879 -
   1.880 -    /// \e
   1.881 -    bool header(const std::string& line) {
   1.882 -      std::cout << "Asked header: " << line << std::endl; 
   1.883 -      return true;
   1.884 -    }
   1.885 -
   1.886 -    /// \e
   1.887 -    void read(std::istream& is) {
   1.888 -      std::string line;
   1.889 -      while (std::getline(is, line)) {
   1.890 -	std::cout << line << std::endl;
   1.891 -      }
   1.892 -    }
   1.893 -  
   1.894 -  };
   1.895 -
   1.896 -  /// @}
   1.897  }
   1.898  #endif