2 * src/lemon/lemon_reader.h - Part of LEMON, a generic C++ optimization library
4 * Copyright (C) 2005 Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
5 * (Egervary Research Group on Combinatorial Optimization, EGRES).
7 * Permission to use, modify and distribute this software is granted
8 * provided that this copyright notice appears in all copies. For
9 * precise terms see the accompanying LICENSE file.
11 * This software is provided "AS IS" with no warranty of any kind,
12 * express or implied, and with no claim as to its suitability for any
19 ///\brief Lemon Format reader.
21 #ifndef LEMON_LEMON_READER_H
22 #define LEMON_LEMON_READER_H
32 #include <lemon/error.h>
33 #include <lemon/bits/item_reader.h>
39 /// \brief Lemon Format reader class.
41 /// The Lemon Format contains several sections. We do not want to
42 /// determine what sections are in a lemon file we give only a framework
43 /// to read a section oriented format.
45 /// In the Lemon Format each section starts with a line contains a \c \@
46 /// character on the first not white space position. This line is the
47 /// header line of the section. Each next lines belong to this section
48 /// while it does not starts with \c \@ character. This line can start a
49 /// new section or if it can close the file with the \c \@end line.
50 /// The file format ignore the empty lines and it may contain comments
51 /// started with a \c # character to the end of the line.
53 /// The framework provides an abstract LemonReader::SectionReader class
54 /// what defines the interface of a SectionReader. The SectionReader
55 /// has the \c header() member function what get a header line string and
56 /// decides if it want to process the next section. Several SectionReaders
57 /// can be attached to an LemonReader and the first attached what can
58 /// process the section will be used. Its \c read() member will called
59 /// with a stream contains the section. From this stream the empty lines
60 /// and comments are filtered out.
62 /// \relates GraphReader
63 /// \relates NodeSetReader
64 /// \relates EdgeSetReader
65 /// \relates NodesReader
66 /// \relates EdgesReader
67 /// \relates AttributeReader
71 class FilterStreamBuf : public std::streambuf {
74 typedef std::streambuf Parent;
75 typedef Parent::char_type char_type;
76 FilterStreamBuf(std::istream& is, int& num)
77 : _is(is), _base(0), _eptr(0),
78 _num(num), skip_state(after_endl) {}
82 enum skip_state_type {
89 char_type small_buf[1];
99 skip_state_type skip_state;
102 char_type* base() { return _base; }
104 char_type* eptr() { return _eptr; }
106 int blen() { return _eptr - _base; }
108 void setb(char_type* buf, int len) {
113 virtual std::streambuf* setbuf(char *buf, int len) {
114 if (base()) return 0;
115 if (buf != 0 && len >= (int)sizeof(small_buf)) {
118 setb(small_buf, sizeof(small_buf));
124 bool put_char(char c) {
125 switch (skip_state) {
129 skip_state = after_endl;
132 skip_state = after_comment;
140 skip_state = after_endl;
152 skip_state = empty_line;
156 skip_state = no_skip;
166 skip_state = after_endl;
175 virtual int underflow() {
177 if (_is.read(&c, 1)) {
186 for (ptr = base(); ptr != eptr(); ++ptr) {
187 if (_is.read(&c, 1)) {
188 if (c == '\n') ++_num;
192 if (skip_state == after_endl && c == '@') {
202 setg(base(), base(), ptr);
213 /// \brief Abstract base class for reading a section.
215 /// This class has an \c header() member function what get a
216 /// header line string and decides if it want to process the next
217 /// section. Several SectionReaders can be attached to an LemonReader
218 /// and the first attached what can process the section will be used.
219 /// Its \c read() member will called with a stream contains the section.
220 /// From this stream the empty lines and comments are filtered out.
221 class SectionReader {
222 friend class LemonReader;
224 /// \brief Constructor for SectionReader.
226 /// Constructor for SectionReader. It attach this reader to
227 /// the given LemonReader.
228 SectionReader(LemonReader& reader) {
229 reader.attach(*this);
232 /// \brief Gives back true when the SectionReader can process
233 /// the section with the given header line.
235 /// It gives back true when the SectionReader can process
236 /// the section with the given header line.
237 virtual bool header(const std::string& line) = 0;
239 /// \brief Reader function of the section.
241 /// It reads the content of the section.
242 virtual void read(std::istream& is) = 0;
245 /// \brief Constructor for LemonReader.
247 /// Constructor for LemonReader which reads from the given stream.
248 LemonReader(std::istream& _is)
249 : is(&_is), own_is(false) {}
251 /// \brief Constructor for LemonReader.
253 /// Constructor for LemonReader which reads from the given file.
254 LemonReader(const std::string& filename)
255 : is(0), own_is(true) {
256 is = new std::ifstream(filename.c_str());
259 /// \brief Desctructor for LemonReader.
261 /// Desctructor for LemonReader.
269 LemonReader(const LemonReader&);
270 void operator=(const LemonReader&);
272 void attach(SectionReader& reader) {
273 readers.push_back(&reader);
277 /// \brief Executes the LemonReader.
279 /// It executes the LemonReader.
284 while ((++line_num, getline(*is, line)) && line.find("@end") != 0) {
285 SectionReaders::iterator it;
286 for (it = readers.begin(); it != readers.end(); ++it) {
287 if ((*it)->header(line)) {
289 FilterStreamBuf buffer(*is, line_num);
290 buffer.pubsetbuf(buf, sizeof(buf));
291 std::istream is(&buffer);
297 } catch (DataFormatError& error) {
298 error.line(line_num);
309 typedef std::vector<SectionReader*> SectionReaders;
310 SectionReaders readers;
314 /// \brief Helper class for implementing the common SectionReaders.
316 /// Helper class for implementing the common SectionReaders.
317 class CommonSectionReaderBase : public LemonReader::SectionReader {
318 typedef LemonReader::SectionReader Parent;
321 /// \brief Constructor for CommonSectionReaderBase.
323 /// Constructor for CommonSectionReaderBase. It attach this reader to
324 /// the given LemonReader.
325 CommonSectionReaderBase(LemonReader& _reader)
328 template <typename _Item>
331 template <typename _Item>
332 class InverterBase : public ReaderBase<_Item> {
335 virtual void read(std::istream&, const Item&) = 0;
336 virtual Item read(std::istream&) const = 0;
338 virtual InverterBase<_Item>* getInverter() {
345 template <typename _Item, typename _Map, typename _Reader>
346 class MapReaderInverter : public InverterBase<_Item> {
349 typedef _Reader Reader;
350 typedef typename Reader::Value Value;
352 typedef std::map<Value, Item> Inverse;
358 MapReaderInverter(Map& _map, const Reader& _reader)
359 : map(_map), reader(_reader) {}
361 virtual ~MapReaderInverter() {}
363 virtual void read(std::istream& is, const Item& item) {
365 reader.read(is, value);
366 map.set(item, value);
367 typename Inverse::iterator it = inverse.find(value);
368 if (it == inverse.end()) {
369 inverse.insert(std::make_pair(value, item));
371 throw DataFormatError("Multiple ID occurence");
375 virtual Item read(std::istream& is) const {
377 reader.read(is, value);
378 typename Inverse::const_iterator it = inverse.find(value);
379 if (it != inverse.end()) {
382 throw DataFormatError("Invalid ID error");
388 template <typename _Item, typename _Reader>
389 class SkipReaderInverter : public InverterBase<_Item> {
392 typedef _Reader Reader;
393 typedef typename Reader::Value Value;
394 typedef std::map<Value, Item> Inverse;
398 SkipReaderInverter(const Reader& _reader)
401 virtual ~SkipReaderInverter() {}
403 virtual void read(std::istream& is, const Item& item) {
405 reader.read(is, value);
406 typename Inverse::iterator it = inverse.find(value);
407 if (it == inverse.end()) {
408 inverse.insert(std::make_pair(value, item));
410 throw DataFormatError("Multiple ID occurence error");
414 virtual Item read(std::istream& is) const {
416 reader.read(is, value);
417 typename Inverse::const_iterator it = inverse.find(value);
418 if (it != inverse.end()) {
421 throw DataFormatError("Invalid ID error");
431 template <typename _Item>
436 virtual ~ReaderBase() {}
438 virtual void read(std::istream& is, const Item& item) = 0;
439 virtual InverterBase<_Item>* getInverter() = 0;
442 template <typename _Item, typename _Map, typename _Reader>
443 class MapReader : public ReaderBase<_Item> {
446 typedef _Reader Reader;
447 typedef typename Reader::Value Value;
453 MapReader(Map& _map, const Reader& _reader)
454 : map(_map), reader(_reader) {}
456 virtual ~MapReader() {}
458 virtual void read(std::istream& is, const Item& item) {
460 reader.read(is, value);
461 map.set(item, value);
464 virtual InverterBase<_Item>* getInverter() {
465 return new MapReaderInverter<Item, Map, Reader>(map, reader);
470 template <typename _Item, typename _Reader>
471 class SkipReader : public ReaderBase<_Item> {
473 typedef _Reader Reader;
474 typedef typename Reader::Value Value;
478 SkipReader(const Reader& _reader) : reader(_reader) {}
480 virtual ~SkipReader() {}
482 virtual void read(std::istream& is, const Item&) {
484 reader.read(is, value);
487 virtual InverterBase<Item>* getInverter() {
488 return new SkipReaderInverter<Item, Reader>(reader);
492 template <typename _Item>
496 virtual Item read(std::istream& is) const = 0;
499 template <typename _Item, typename _BoxedIdReader>
500 class IdReader : public IdReaderBase<_Item> {
503 typedef _BoxedIdReader BoxedIdReader;
505 const BoxedIdReader& boxedIdReader;
507 IdReader(const BoxedIdReader& _boxedIdReader)
508 : boxedIdReader(_boxedIdReader) {}
510 virtual Item read(std::istream& is) const {
511 return boxedIdReader.readId(is);
515 class ValueReaderBase {
517 virtual void read(std::istream&) {};
520 template <typename _Value, typename _Reader>
521 class ValueReader : public ValueReaderBase {
523 typedef _Value Value;
524 typedef _Reader Reader;
526 ValueReader(Value& _value, const Reader& _reader)
527 : value(_value), reader(_reader) {}
529 virtual void read(std::istream& is) {
530 reader.read(is, value);
539 /// \ingroup io_group
540 /// \brief SectionReader for reading a graph's nodeset.
542 /// The lemon format can store multiple graph nodesets with several maps.
543 /// The nodeset section's header line is \c \@nodeset \c nodeset_id, but the
544 /// \c nodeset_id may be empty.
546 /// The first line of the section contains the names of the maps separated
547 /// with white spaces. Each next lines describes a node in the nodeset, and
548 /// contains the mapped values for each map.
550 /// If the nodeset contains an \c "id" named map then it will be regarded
551 /// as id map. This map should contain only unique values and when the
552 /// \c readId() member will read a value from the given stream it will
553 /// give back that node which is mapped to this value.
555 /// \relates LemonReader
556 template <typename _Graph, typename _Traits = DefaultReaderTraits>
557 class NodeSetReader : public CommonSectionReaderBase {
558 typedef CommonSectionReaderBase Parent;
561 typedef _Graph Graph;
562 typedef _Traits Traits;
563 typedef typename Graph::Node Item;
564 typedef typename Traits::Skipper DefaultSkipper;
566 /// \brief Constructor.
568 /// Constructor for NodeSetReader. It creates the NodeSetReader and
569 /// attach it into the given LemonReader. The nodeset reader will
570 /// add the readed nodes to the given Graph. The reader will read
571 /// the section when the \c section_id and the \c _id are the same.
572 NodeSetReader(LemonReader& _reader, Graph& _graph,
573 const std::string& _id = std::string(),
574 const DefaultSkipper& _skipper = DefaultSkipper())
575 : Parent(_reader), graph(_graph), id(_id), skipper(_skipper) {}
578 /// \brief Destructor.
580 /// Destructor for NodeSetReader.
581 virtual ~NodeSetReader() {
582 for (typename MapReaders::iterator it = readers.begin();
583 it != readers.end(); ++it) {
589 NodeSetReader(const NodeSetReader&);
590 void operator=(const NodeSetReader&);
594 /// \brief Add a new node map reader command for the reader.
596 /// Add a new node map reader command for the reader.
597 template <typename Map>
598 NodeSetReader& readMap(std::string name, Map& map) {
599 return readMap<typename Traits::
600 template Reader<typename Map::Value>, Map>(name, map);
603 /// \brief Add a new node map reader command for the reader.
605 /// Add a new node map reader command for the reader.
606 template <typename Reader, typename Map>
607 NodeSetReader& readMap(std::string name, Map& map,
608 const Reader& reader = Reader()) {
609 if (readers.find(name) != readers.end()) {
611 msg << "Multiple read rule for node map: " << name;
612 throw IOParameterError(msg.message());
615 make_pair(name, new MapReader<Item, Map, Reader>(map, reader)));
619 /// \brief Add a new node map skipper command for the reader.
621 /// Add a new node map skipper command for the reader.
622 template <typename Reader>
623 NodeSetReader& skipMap(std::string name,
624 const Reader& reader = Reader()) {
625 if (readers.find(name) != readers.end()) {
627 msg << "Multiple read rule for node map: " << name;
628 throw IOParameterError(msg.message());
630 readers.insert(make_pair(name, new SkipReader<Item, Reader>(reader)));
636 /// \brief Gives back true when the SectionReader can process
637 /// the section with the given header line.
639 /// It gives back true when the header line starts with \c @nodeset,
640 /// and the header line's id and the nodeset's id are the same.
641 virtual bool header(const std::string& line) {
642 std::istringstream ls(line);
645 ls >> command >> name;
646 return command == "@nodeset" && name == id;
649 /// \brief Reader function of the section.
651 /// It reads the content of the section.
652 virtual void read(std::istream& is) {
653 std::vector<ReaderBase<Item>* > index;
657 std::istringstream ls(line);
659 typename MapReaders::iterator it = readers.find(id);
660 if (it != readers.end()) {
661 index.push_back(it->second);
663 index.push_back(&skipper);
665 if (id == "id" && inverter.get() == 0) {
666 inverter.reset(index.back()->getInverter());
667 index.back() = inverter.get();
670 while (getline(is, line)) {
671 typename Graph::Node node = graph.addNode();
672 std::istringstream ls(line);
673 for (int i = 0; i < (int)index.size(); ++i) {
674 index[i]->read(ls, node);
681 /// \brief Returns true if the nodeset can give back the node by its id.
683 /// Returns true if the nodeset can give back the node by its id.
684 /// It is possible only if an "id" named map was read.
685 bool isIdReader() const {
686 return inverter.get() != 0;
689 /// \brief Gives back the node by its id.
691 /// It reads an id from the stream and gives back which node belongs to
692 /// it. It is possible only if there was read an "id" named map.
693 typename Graph::Node readId(std::istream& is) const {
694 return inverter->read(is);
699 typedef std::map<std::string, ReaderBase<Item>*> MapReaders;
704 SkipReader<Item, DefaultSkipper> skipper;
706 std::auto_ptr<InverterBase<Item> > inverter;
709 /// \ingroup io_group
710 /// \brief SectionReader for reading a graph's edgeset.
712 /// The lemon format can store multiple graph edgesets with several maps.
713 /// The edgeset section's header line is \c \@edgeset \c edgeset_id, but the
714 /// \c edgeset_id may be empty.
716 /// The first line of the section contains the names of the maps separated
717 /// with white spaces. Each next lines describes a node in the nodeset. The
718 /// line contains the two nodes' id and the mapped values for each map.
720 /// If the edgeset contains an \c "id" named map then it will be regarded
721 /// as id map. This map should contain only unique values and when the
722 /// \c readId() member will read a value from the given stream it will
723 /// give back that edge which is mapped to this value.
725 /// The edgeset reader needs a node id reader to identify which nodes
726 /// have to be connected. If a NodeSetReader reads an "id" named map,
727 /// it will be able to resolve the nodes by ids.
729 /// \relates LemonReader
730 template <typename _Graph, typename _Traits = DefaultReaderTraits>
731 class EdgeSetReader : public CommonSectionReaderBase {
732 typedef CommonSectionReaderBase Parent;
735 typedef _Graph Graph;
736 typedef _Traits Traits;
737 typedef typename Graph::Edge Item;
738 typedef typename Traits::Skipper DefaultSkipper;
740 /// \brief Constructor.
742 /// Constructor for EdgeSetReader. It creates the EdgeSetReader and
743 /// attach it into the given LemonReader. The edgeset reader will
744 /// add the readed edges to the given Graph. It will use the given
745 /// node id reader to read the source and target nodes of the edges.
746 /// The reader will read the section only if the \c _id and the
747 /// \c edgset_id are the same.
748 template <typename NodeIdReader>
749 EdgeSetReader(LemonReader& _reader, Graph& _graph,
750 const NodeIdReader& _nodeIdReader,
751 const std::string& _id = std::string(),
752 const DefaultSkipper& _skipper = DefaultSkipper())
753 : Parent(_reader), graph(_graph), id(_id), skipper(_skipper),
754 nodeIdReader(new IdReader<typename Graph::Node, NodeIdReader>
757 /// \brief Destructor.
759 /// Destructor for EdgeSetReader.
760 virtual ~EdgeSetReader() {
761 for (typename MapReaders::iterator it = readers.begin();
762 it != readers.end(); ++it) {
768 EdgeSetReader(const EdgeSetReader&);
769 void operator=(const EdgeSetReader&);
773 /// \brief Add a new edge map reader command for the reader.
775 /// Add a new edge map reader command for the reader.
776 template <typename Map>
777 EdgeSetReader& readMap(std::string name, Map& map) {
778 return readMap<typename Traits::
779 template Reader<typename Map::Value>, Map>(name, map);
782 /// \brief Add a new edge map reader command for the reader.
784 /// Add a new edge map reader command for the reader.
785 template <typename Reader, typename Map>
786 EdgeSetReader& readMap(std::string name, Map& map,
787 const Reader& reader = Reader()) {
788 if (readers.find(name) != readers.end()) {
790 msg << "Multiple read rule for edge map: " << name;
791 throw IOParameterError(msg.message());
794 make_pair(name, new MapReader<Item, Map, Reader>(map, reader)));
798 /// \brief Add a new edge map skipper command for the reader.
800 /// Add a new edge map skipper command for the reader.
801 template <typename Reader>
802 EdgeSetReader& skipMap(std::string name,
803 const Reader& reader = Reader()) {
804 if (readers.find(name) != readers.end()) {
806 msg << "Multiple read rule for node map: " << name;
807 throw IOParameterError(msg.message());
809 readers.insert(make_pair(name, new SkipReader<Item, Reader>(reader)));
815 /// \brief Gives back true when the SectionReader can process
816 /// the section with the given header line.
818 /// It gives back true when the header line starts with \c @edgeset,
819 /// and the header line's id and the edgeset's id are the same.
820 virtual bool header(const std::string& line) {
821 std::istringstream ls(line);
824 ls >> command >> name;
825 return command == "@edgeset" && name == id;
828 /// \brief Reader function of the section.
830 /// It reads the content of the section.
831 virtual void read(std::istream& is) {
832 std::vector<ReaderBase<Item>* > index;
836 std::istringstream ls(line);
838 typename MapReaders::iterator it = readers.find(id);
839 if (it != readers.end()) {
840 index.push_back(it->second);
842 index.push_back(&skipper);
844 if (id == "id" && inverter.get() == 0) {
845 inverter.reset(index.back()->getInverter());
846 index.back() = inverter.get();
849 while (getline(is, line)) {
850 std::istringstream ls(line);
851 typename Graph::Node from = nodeIdReader->read(ls);
852 typename Graph::Node to = nodeIdReader->read(ls);
853 typename Graph::Edge edge = graph.addEdge(from, to);
854 for (int i = 0; i < (int)index.size(); ++i) {
855 index[i]->read(ls, edge);
862 /// \brief Returns true if the edgeset can give back the edge by its id.
864 /// Returns true if the edgeset can give back the edge by its id.
865 /// It is possible only if an "id" named map was read.
866 bool isIdReader() const {
867 return inverter.get() != 0;
870 /// \brief Gives back the edge by its id.
872 /// It reads an id from the stream and gives back which edge belongs to
873 /// it. It is possible only if there was read an "id" named map.
874 typename Graph::Edge readId(std::istream& is) const {
875 return inverter->read(is);
880 typedef std::map<std::string, ReaderBase<Item>*> MapReaders;
885 SkipReader<Item, DefaultSkipper> skipper;
887 std::auto_ptr<InverterBase<Item> > inverter;
888 std::auto_ptr<IdReaderBase<typename Graph::Node> > nodeIdReader;
891 /// \ingroup io_group
892 /// \brief SectionReader for reading labeled nodes.
894 /// The nodes section's header line is \c \@nodes \c nodes_id, but the
895 /// \c nodes_id may be empty.
897 /// Each line in the section contains the name of the node
898 /// and then the node id.
900 /// \relates LemonReader
901 template <typename _Graph>
902 class NodeReader : public CommonSectionReaderBase {
903 typedef CommonSectionReaderBase Parent;
904 typedef _Graph Graph;
905 typedef typename Graph::Node Item;
908 /// \brief Constructor.
910 /// Constructor for NodeReader. It creates the NodeReader and
911 /// attach it into the given LemonReader. It will use the given
912 /// node id reader to give back the nodes. The reader will read the
913 /// section only if the \c _id and the \c nodes_id are the same.
914 template <typename _IdReader>
915 NodeReader(LemonReader& _reader, const _IdReader& _idReader,
916 const std::string& _id = std::string())
917 : Parent(_reader), id(_id),
918 idReader(new IdReader<typename Graph::Node, _IdReader>(_idReader)) {}
920 /// \brief Destructor.
922 /// Destructor for NodeReader.
923 virtual ~NodeReader() {}
926 NodeReader(const NodeReader&);
927 void operator=(const NodeReader&);
931 /// \brief Add a node reader command for the NodeReader.
933 /// Add a node reader command for the NodeReader.
934 void readNode(const std::string& name, Item& item) {
935 if (readers.find(name) != readers.end()) {
937 msg << "Multiple read rule for node: " << name;
938 throw IOParameterError(msg.message());
940 readers.insert(make_pair(name, &item));
945 /// \brief Gives back true when the SectionReader can process
946 /// the section with the given header line.
948 /// It gives back true when the header line start with \c @nodes,
949 /// and the header line's id and the reader's id are the same.
950 virtual bool header(const std::string& line) {
951 std::istringstream ls(line);
954 ls >> command >> name;
955 return command == "@nodes" && name == id;
958 /// \brief Reader function of the section.
960 /// It reads the content of the section.
961 virtual void read(std::istream& is) {
963 while (getline(is, line)) {
964 std::istringstream ls(line);
967 typename ItemReaders::iterator it = readers.find(id);
968 if (it != readers.end()) {
969 *(it->second) = idReader->read(ls);
978 typedef std::map<std::string, Item*> ItemReaders;
980 std::auto_ptr<IdReaderBase<Item> > idReader;
983 /// \ingroup io_group
984 /// \brief SectionReader for reading labeled edges.
986 /// The edges section's header line is \c \@edges \c edges_id, but the
987 /// \c edges_id may be empty.
989 /// Each line in the section contains the name of the edge
990 /// and then the edge id.
992 /// \relates LemonReader
993 template <typename _Graph>
994 class EdgeReader : public CommonSectionReaderBase {
995 typedef CommonSectionReaderBase Parent;
996 typedef _Graph Graph;
997 typedef typename Graph::Edge Item;
1000 /// \brief Constructor.
1002 /// Constructor for EdgeReader. It creates the EdgeReader and
1003 /// attach it into the given LemonReader. It will use the given
1004 /// edge id reader to give back the edges. The reader will read the
1005 /// section only if the \c _id and the \c nodes_id are the same.
1006 template <typename _IdReader>
1007 EdgeReader(LemonReader& _reader, const _IdReader& _idReader,
1008 const std::string& _id = std::string())
1009 : Parent(_reader), id(_id),
1010 idReader(new IdReader<typename Graph::Edge, _IdReader>(_idReader)) {}
1012 /// \brief Destructor.
1014 /// Destructor for EdgeReader.
1015 virtual ~EdgeReader() {}
1017 EdgeReader(const EdgeReader&);
1018 void operator=(const EdgeReader&);
1022 /// \brief Add an edge reader command for the EdgeReader.
1024 /// Add an edge reader command for the EdgeReader.
1025 void readEdge(const std::string& name, Item& item) {
1026 if (readers.find(name) != readers.end()) {
1028 msg << "Multiple read rule for edge: " << name;
1029 throw IOParameterError(msg.message());
1031 readers.insert(make_pair(name, &item));
1036 /// \brief Gives back true when the SectionReader can process
1037 /// the section with the given header line.
1039 /// It gives back true when the header line start with \c @edges,
1040 /// and the header line's id and the reader's id are the same.
1041 virtual bool header(const std::string& line) {
1042 std::istringstream ls(line);
1043 std::string command;
1045 ls >> command >> name;
1046 return command == "@edges" && name == id;
1049 /// \brief Reader function of the section.
1051 /// It reads the content of the section.
1052 virtual void read(std::istream& is) {
1054 while (getline(is, line)) {
1055 std::istringstream ls(line);
1058 typename ItemReaders::iterator it = readers.find(id);
1059 if (it != readers.end()) {
1060 *(it->second) = idReader->read(ls);
1069 typedef std::map<std::string, Item*> ItemReaders;
1070 ItemReaders readers;
1071 std::auto_ptr<IdReaderBase<Item> > idReader;
1074 /// \ingroup io_group
1075 /// \brief SectionReader for attributes.
1077 /// The lemon format can store multiple attribute set. Each set has
1078 /// the header line \c \@attributes \c attributeset_id, but the
1079 /// attributeset_id may be empty.
1081 /// The attributeset section contains several lines. Each of them starts
1082 /// with an attribute and then a the value for the id.
1084 /// \relates LemonReader
1085 template <typename _Traits = DefaultReaderTraits>
1086 class AttributeReader : public CommonSectionReaderBase {
1087 typedef CommonSectionReaderBase Parent;
1088 typedef _Traits Traits;
1090 /// \brief Constructor.
1092 /// Constructor for AttributeReader. It creates the AttributeReader and
1093 /// attach it into the given LemonReader. The reader process a section
1094 /// only if the \c section_id and the \c _id are the same.
1095 AttributeReader(LemonReader& _reader,
1096 const std::string& _id = std::string())
1097 : Parent(_reader), id(_id) {}
1099 /// \brief Destructor.
1101 /// Destructor for AttributeReader.
1102 virtual ~AttributeReader() {
1103 for (typename Readers::iterator it = readers.begin();
1104 it != readers.end(); ++it) {
1110 AttributeReader(const AttributeReader&);
1111 void operator=(AttributeReader&);
1114 /// \brief Add an attribute reader command for the reader.
1116 /// Add an attribute reader command for the reader.
1117 template <typename Value>
1118 AttributeReader& readAttribute(const std::string& id, Value& value) {
1119 return readAttribute<typename Traits::template Reader<Value> >
1123 /// \brief Add an attribute reader command for the reader.
1125 /// Add an attribute reader command for the reader.
1126 template <typename Reader, typename Value>
1127 AttributeReader& readAttribute(const std::string& name, Value& value,
1128 const Reader& reader = Reader()) {
1129 if (readers.find(name) != readers.end()) {
1131 msg << "Multiple read rule for attribute: " << name;
1132 throw IOParameterError(msg.message());
1134 readers.insert(make_pair(name, new ValueReader<Value, Reader>
1141 /// \brief Gives back true when the SectionReader can process
1142 /// the section with the given header line.
1144 /// It gives back true when the header line start with \c @attributes,
1145 /// and the header line's id and the attributeset's id are the same.
1146 bool header(const std::string& line) {
1147 std::istringstream ls(line);
1148 std::string command;
1150 ls >> command >> name;
1151 return command == "@attributes" && name == id;
1154 /// \brief Reader function of the section.
1156 /// It reads the content of the section.
1157 void read(std::istream& is) {
1159 while (getline(is, line)) {
1160 std::istringstream ls(line);
1163 typename Readers::iterator it = readers.find(id);
1164 if (it != readers.end()) {
1165 it->second->read(ls);
1173 typedef std::map<std::string, ValueReaderBase*> Readers;