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