Two minor changes.
DefaultReader<std::string>
comment lines
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.
22 #ifndef LEMON_LEMON_READER_H
23 #define LEMON_LEMON_READER_H
34 #include <lemon/error.h>
35 #include <lemon/graph_utils.h>
36 #include <lemon/utility.h>
37 #include <lemon/bits/item_reader.h>
42 namespace _reader_bits {
45 bool operator<(T, T) {
46 throw DataFormatError("Id is not comparable");
51 bool operator()(const T& p, const T& q) const {
56 template <typename M1, typename M2>
57 class WriteComposeMap {
59 typedef True NeedCopy;
61 typedef typename M2::Key Key;
62 typedef typename M1::Value Value;
64 WriteComposeMap(typename SmartParameter<M1>::Type _m1, const M2& _m2)
67 void set(const Key& key, const Value& value) {
68 m1.set(m2[key], value);
73 typename SmartReference<M1>::Type m1;
74 typename SmartConstReference<M2>::Type m2;
78 template <typename M1, typename M2>
79 WriteComposeMap<M1, M2> writeComposeMap(M1& m1, const M2& m2) {
80 return WriteComposeMap<M1, M2>(m1, m2);
83 template <typename M1, typename M2>
84 WriteComposeMap<M1, M2> writeComposeMap(const M1& m1, const M2& m2) {
85 return WriteComposeMap<M1, M2>(m1, m2);
91 /// \brief Lemon Format reader class.
93 /// The Lemon Format contains several sections. We do not want to
94 /// determine what sections are in a lemon file we give only a framework
95 /// to read a section oriented format.
97 /// In the Lemon Format each section starts with a line contains a \c \@
98 /// character on the first not white space position. This line is the
99 /// header line of the section. Each next lines belong to this section
100 /// while it does not starts with \c \@ character. This line can start a
101 /// new section or if it can close the file with the \c \@end line.
102 /// The file format ignore the empty and comment lines. The line is
103 /// comment line if it starts with a \c # character.
105 /// The framework provides an abstract LemonReader::SectionReader class
106 /// what defines the interface of a SectionReader. The SectionReader
107 /// has the \c header() member function what get a header line string and
108 /// decides if it want to process the next section. Several SectionReaders
109 /// can be attached to an LemonReader and the first attached what can
110 /// process the section will be used. Its \c read() member will called
111 /// with a stream contains the section. From this stream the empty and
112 /// comment lines are filtered out.
114 /// \relates GraphReader
115 /// \relates NodeSetReader
116 /// \relates EdgeSetReader
117 /// \relates NodesReader
118 /// \relates EdgesReader
119 /// \relates AttributeReader
123 class FilterStreamBuf : public std::streambuf {
126 typedef std::streambuf Parent;
127 typedef Parent::char_type char_type;
128 FilterStreamBuf(std::istream& is, int& num)
129 : _is(is), _base(0), _eptr(0),
130 _num(num), skip_state(after_endl) {}
134 enum skip_state_type {
140 char_type small_buf[1];
150 skip_state_type skip_state;
153 char_type* base() { return _base; }
155 char_type* eptr() { return _eptr; }
157 int blen() { return _eptr - _base; }
159 void setb(char_type* buf, int len) {
164 virtual std::streambuf* setbuf(char *buf, int len) {
165 if (base()) return 0;
166 if (buf != 0 && len >= (int)sizeof(small_buf)) {
169 setb(small_buf, sizeof(small_buf));
175 bool put_char(char c) {
176 switch (skip_state) {
180 skip_state = after_endl;
192 skip_state = comment_line;
196 skip_state = no_skip;
206 skip_state = after_endl;
215 virtual int underflow() {
217 if (_is.read(&c, 1)) {
226 for (ptr = base(); ptr != eptr(); ++ptr) {
227 if (_is.read(&c, 1)) {
228 if (c == '\n') ++_num;
232 if (skip_state == after_endl && c == '@') {
242 setg(base(), base(), ptr);
253 /// \brief Abstract base class for reading a section.
255 /// This class has an \c header() member function what get a
256 /// header line string and decides if it want to process the next
257 /// section. Several SectionReaders can be attached to an LemonReader
258 /// and the first attached what can process the section will be used.
259 /// Its \c read() member will called with a stream contains the section.
260 /// From this stream the empty lines and comments are filtered out.
261 class SectionReader {
262 friend class LemonReader;
264 /// \brief Constructor for SectionReader.
266 /// Constructor for SectionReader. It attach this reader to
267 /// the given LemonReader.
268 SectionReader(LemonReader& reader) {
269 reader.attach(*this);
272 /// \brief Gives back true when the SectionReader can process
273 /// the section with the given header line.
275 /// It gives back true when the SectionReader can process
276 /// the section with the given header line.
277 virtual bool header(const std::string& line) = 0;
279 /// \brief Reader function of the section.
281 /// It reads the content of the section.
282 virtual void read(std::istream& is) = 0;
285 /// \brief Constructor for LemonReader.
287 /// Constructor for LemonReader which reads from the given stream.
288 LemonReader(std::istream& _is)
289 : is(&_is), own_is(false) {}
291 /// \brief Constructor for LemonReader.
293 /// Constructor for LemonReader which reads from the given file.
294 LemonReader(const std::string& filename)
295 : is(0), own_is(true) {
296 is = new std::ifstream(filename.c_str());
299 /// \brief Desctructor for LemonReader.
301 /// Desctructor for LemonReader.
309 LemonReader(const LemonReader&);
310 void operator=(const LemonReader&);
312 void attach(SectionReader& reader) {
313 readers.push_back(&reader);
317 /// \brief Executes the LemonReader.
319 /// It executes the LemonReader.
324 while ((++line_num, getline(*is, line)) && line.find("@end") != 0) {
325 SectionReaders::iterator it;
326 for (it = readers.begin(); it != readers.end(); ++it) {
327 if ((*it)->header(line)) {
329 FilterStreamBuf buffer(*is, line_num);
330 buffer.pubsetbuf(buf, sizeof(buf));
331 std::istream is(&buffer);
337 } catch (DataFormatError& error) {
338 error.line(line_num);
349 typedef std::vector<SectionReader*> SectionReaders;
350 SectionReaders readers;
354 /// \brief Helper class for implementing the common SectionReaders.
356 /// Helper class for implementing the common SectionReaders.
357 class CommonSectionReaderBase : public LemonReader::SectionReader {
358 typedef LemonReader::SectionReader Parent;
361 /// \brief Constructor for CommonSectionReaderBase.
363 /// Constructor for CommonSectionReaderBase. It attach this reader to
364 /// the given LemonReader.
365 CommonSectionReaderBase(LemonReader& _reader)
368 template <typename _Item>
371 template <typename _Item>
372 class InverterBase : public ReaderBase<_Item> {
375 virtual void read(std::istream&, const Item&) = 0;
376 virtual Item read(std::istream&) const = 0;
378 virtual InverterBase<_Item>* getInverter() {
383 template <typename _Item, typename _Map, typename _Reader>
384 class MapReaderInverter : public InverterBase<_Item> {
387 typedef _Reader Reader;
388 typedef typename Reader::Value Value;
390 typedef std::map<Value, Item, _reader_bits::Less<Value> > Inverse;
392 typename SmartReference<Map>::Type map;
396 MapReaderInverter(typename SmartParameter<Map>::Type _map,
397 const Reader& _reader)
398 : map(_map), reader(_reader) {}
400 virtual ~MapReaderInverter() {}
402 virtual void read(std::istream& is, const Item& item) {
404 reader.read(is, value);
405 map.set(item, 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");
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");
426 template <typename _Item, typename _Reader>
427 class SkipReaderInverter : public InverterBase<_Item> {
430 typedef _Reader Reader;
431 typedef typename Reader::Value Value;
432 typedef std::map<Value, Item, _reader_bits::Less<Value> > Inverse;
436 SkipReaderInverter(const Reader& _reader)
439 virtual ~SkipReaderInverter() {}
441 virtual void read(std::istream& is, const Item& item) {
443 reader.read(is, value);
444 typename Inverse::iterator it = inverse.find(value);
445 if (it == inverse.end()) {
446 inverse.insert(std::make_pair(value, item));
448 throw DataFormatError("Multiple ID occurence error");
452 virtual Item read(std::istream& is) const {
454 reader.read(is, value);
455 typename Inverse::const_iterator it = inverse.find(value);
456 if (it != inverse.end()) {
459 throw DataFormatError("Invalid ID error");
467 template <typename _Item>
472 virtual ~ReaderBase() {}
474 virtual void read(std::istream& is, const Item& item) = 0;
475 virtual InverterBase<_Item>* getInverter() = 0;
478 template <typename _Item, typename _Map, typename _Reader>
479 class MapReader : public ReaderBase<_Item> {
482 typedef _Reader Reader;
483 typedef typename Reader::Value Value;
486 typename SmartReference<Map>::Type map;
489 MapReader(typename SmartParameter<Map>::Type _map,
490 const Reader& _reader)
491 : map(_map), reader(_reader) {}
493 virtual ~MapReader() {}
495 virtual void read(std::istream& is, const Item& item) {
497 reader.read(is, value);
498 map.set(item, value);
501 virtual InverterBase<_Item>* getInverter() {
502 return new MapReaderInverter<Item, Map, Reader>(map, reader);
507 template <typename _Item, typename _Reader>
508 class SkipReader : public ReaderBase<_Item> {
510 typedef _Reader Reader;
511 typedef typename Reader::Value Value;
515 SkipReader(const Reader& _reader) : reader(_reader) {}
517 virtual ~SkipReader() {}
519 virtual void read(std::istream& is, const Item&) {
521 reader.read(is, value);
524 virtual InverterBase<Item>* getInverter() {
525 return new SkipReaderInverter<Item, Reader>(reader);
529 template <typename _Item>
533 virtual Item read(std::istream& is) const = 0;
536 template <typename _Item, typename _BoxedIdReader>
537 class IdReader : public IdReaderBase<_Item> {
540 typedef _BoxedIdReader BoxedIdReader;
542 const BoxedIdReader& boxedIdReader;
544 IdReader(const BoxedIdReader& _boxedIdReader)
545 : boxedIdReader(_boxedIdReader) {}
547 virtual Item read(std::istream& is) const {
548 return boxedIdReader.readId(is);
552 class ValueReaderBase {
554 virtual void read(std::istream&) {};
557 template <typename _Value, typename _Reader>
558 class ValueReader : public ValueReaderBase {
560 typedef _Value Value;
561 typedef _Reader Reader;
563 ValueReader(Value& _value, const Reader& _reader)
564 : value(_value), reader(_reader) {}
566 virtual void read(std::istream& is) {
567 reader.read(is, value);
576 /// \ingroup io_group
577 /// \brief SectionReader for reading a graph's nodeset.
579 /// The lemon format can store multiple graph nodesets with several maps.
580 /// The nodeset section's header line is \c \@nodeset \c nodeset_id, but the
581 /// \c nodeset_id may be empty.
583 /// The first line of the section contains the names of the maps separated
584 /// with white spaces. Each next lines describes a node in the nodeset, and
585 /// contains the mapped values for each map.
587 /// If the nodeset contains an \c "id" named map then it will be regarded
588 /// as id map. This map should contain only unique values and when the
589 /// \c readId() member will read a value from the given stream it will
590 /// give back that node which is mapped to this value.
592 /// \relates LemonReader
593 template <typename _Graph, typename _Traits = DefaultReaderTraits>
594 class NodeSetReader : public CommonSectionReaderBase {
595 typedef CommonSectionReaderBase Parent;
598 typedef _Graph Graph;
599 typedef _Traits Traits;
600 typedef typename Graph::Node Item;
601 typedef typename Traits::Skipper DefaultSkipper;
603 /// \brief Constructor.
605 /// Constructor for NodeSetReader. It creates the NodeSetReader and
606 /// attach it into the given LemonReader. The nodeset reader will
607 /// add the readed nodes to the given Graph. The reader will read
608 /// the section when the \c section_id and the \c _id are the same.
609 NodeSetReader(LemonReader& _reader,
610 typename SmartParameter<Graph>::Type _graph,
611 const std::string& _id = std::string(),
612 const DefaultSkipper& _skipper = DefaultSkipper())
613 : Parent(_reader), graph(_graph), id(_id), skipper(_skipper) {}
616 /// \brief Destructor.
618 /// Destructor for NodeSetReader.
619 virtual ~NodeSetReader() {
620 for (typename MapReaders::iterator it = readers.begin();
621 it != readers.end(); ++it) {
627 NodeSetReader(const NodeSetReader&);
628 void operator=(const NodeSetReader&);
632 /// \brief Add a new node map reader command for the reader.
634 /// Add a new node map reader command for the reader.
635 template <typename Map>
636 NodeSetReader& readNodeMap(std::string name, Map& map) {
638 typename Traits::template Reader<typename Map::Value>, Map,
639 typename SmartParameter<Map>::Type>(name, map);
642 template <typename Map>
643 NodeSetReader& readNodeMap(std::string name, const Map& map) {
645 typename Traits::template Reader<typename Map::Value>, Map,
646 typename SmartParameter<Map>::Type>(name, map);
649 /// \brief Add a new node map reader command for the reader.
651 /// Add a new node map reader command for the reader.
652 template <typename Reader, typename Map>
653 NodeSetReader& readNodeMap(std::string name, Map& map,
654 const Reader& reader = Reader()) {
656 typename Traits::template Reader<typename Map::Value>, Map,
657 typename SmartParameter<Map>::Type>(name, map, reader);
660 template <typename Reader, typename Map>
661 NodeSetReader& readNodeMap(std::string name, const Map& map,
662 const Reader& reader = Reader()) {
664 typename Traits::template Reader<typename Map::Value>, Map,
665 typename SmartParameter<Map>::Type>(name, map, reader);
670 template <typename Reader, typename Map, typename MapParameter>
671 NodeSetReader& _readMap(std::string name, MapParameter map,
672 const Reader& reader = Reader()) {
673 if (readers.find(name) != readers.end()) {
675 msg << "Multiple read rule for node map: " << name;
676 throw IOParameterError(msg.message());
679 make_pair(name, new MapReader<Item, Map, Reader>(map, reader)));
685 /// \brief Add a new node map skipper command for the reader.
687 /// Add a new node map skipper command for the reader.
688 template <typename Reader>
689 NodeSetReader& skipNodeMap(std::string name,
690 const Reader& reader = Reader()) {
691 if (readers.find(name) != readers.end()) {
693 msg << "Multiple read rule for node map: " << name;
694 throw IOParameterError(msg.message());
696 readers.insert(make_pair(name, new SkipReader<Item, Reader>(reader)));
702 /// \brief Gives back true when the SectionReader can process
703 /// the section with the given header line.
705 /// It gives back true when the header line starts with \c \@nodeset,
706 /// and the header line's id and the nodeset's id are the same.
707 virtual bool header(const std::string& line) {
708 std::istringstream ls(line);
711 ls >> command >> name;
712 return command == "@nodeset" && name == id;
715 /// \brief Reader function of the section.
717 /// It reads the content of the section.
718 virtual void read(std::istream& is) {
719 std::vector<ReaderBase<Item>* > index;
723 std::istringstream ls(line);
725 typename MapReaders::iterator it = readers.find(id);
726 if (it != readers.end()) {
727 index.push_back(it->second);
729 index.push_back(&skipper);
731 if (id == "id" && inverter.get() == 0) {
732 inverter.reset(index.back()->getInverter());
733 index.back() = inverter.get();
736 while (getline(is, line)) {
737 typename Graph::Node node = graph.addNode();
738 std::istringstream ls(line);
739 for (int i = 0; i < (int)index.size(); ++i) {
740 index[i]->read(ls, node);
747 /// \brief Returns true if the nodeset can give back the node by its id.
749 /// Returns true if the nodeset can give back the node by its id.
750 /// It is possible only if an "id" named map was read.
751 bool isIdReader() const {
752 return inverter.get() != 0;
755 /// \brief Gives back the node by its id.
757 /// It reads an id from the stream and gives back which node belongs to
758 /// it. It is possible only if there was read an "id" named map.
759 Item readId(std::istream& is) const {
760 return inverter->read(is);
765 typedef std::map<std::string, ReaderBase<Item>*> MapReaders;
768 typename SmartReference<Graph>::Type graph;
770 SkipReader<Item, DefaultSkipper> skipper;
772 std::auto_ptr<InverterBase<Item> > inverter;
775 /// \ingroup io_group
776 /// \brief SectionReader for reading a graph's edgeset.
778 /// The lemon format can store multiple graph edgesets with several maps.
779 /// The edgeset section's header line is \c \@edgeset \c edgeset_id, but the
780 /// \c edgeset_id may be empty.
782 /// The first line of the section contains the names of the maps separated
783 /// with white spaces. Each next lines describes an edge in the edgeset. The
784 /// line contains the source and the target nodes' id and the mapped
785 /// values for each map.
787 /// If the edgeset contains an \c "id" named map then it will be regarded
788 /// as id map. This map should contain only unique values and when the
789 /// \c readId() member will read a value from the given stream it will
790 /// give back that edge which is mapped to this value.
792 /// The edgeset reader needs a node id reader to identify which nodes
793 /// have to be connected. If a NodeSetReader reads an "id" named map,
794 /// it will be able to resolve the nodes by ids.
796 /// \relates LemonReader
797 template <typename _Graph, typename _Traits = DefaultReaderTraits>
798 class EdgeSetReader : public CommonSectionReaderBase {
799 typedef CommonSectionReaderBase Parent;
802 typedef _Graph Graph;
803 typedef _Traits Traits;
804 typedef typename Graph::Edge Item;
805 typedef typename Traits::Skipper DefaultSkipper;
807 /// \brief Constructor.
809 /// Constructor for EdgeSetReader. It creates the EdgeSetReader and
810 /// attach it into the given LemonReader. The edgeset reader will
811 /// add the readed edges to the given Graph. It will use the given
812 /// node id reader to read the source and target nodes of the edges.
813 /// The reader will read the section only if the \c _id and the
814 /// \c edgset_id are the same.
815 template <typename NodeIdReader>
816 EdgeSetReader(LemonReader& _reader,
817 typename SmartParameter<Graph>::Type _graph,
818 const NodeIdReader& _nodeIdReader,
819 const std::string& _id = std::string(),
820 const DefaultSkipper& _skipper = DefaultSkipper())
821 : Parent(_reader), graph(_graph), id(_id), skipper(_skipper),
822 nodeIdReader(new IdReader<typename Graph::Node, NodeIdReader>
825 /// \brief Destructor.
827 /// Destructor for EdgeSetReader.
828 virtual ~EdgeSetReader() {
829 for (typename MapReaders::iterator it = readers.begin();
830 it != readers.end(); ++it) {
836 EdgeSetReader(const EdgeSetReader&);
837 void operator=(const EdgeSetReader&);
841 /// \brief Add a new edge map reader command for the reader.
843 /// Add a new edge map reader command for the reader.
844 template <typename Map>
845 EdgeSetReader& readEdgeMap(std::string name, Map& map) {
847 typename Traits::template Reader<typename Map::Value>, Map,
848 typename SmartParameter<Map>::Type>(name, map);
851 template <typename Map>
852 EdgeSetReader& readEdgeMap(std::string name, const Map& map) {
854 typename Traits::template Reader<typename Map::Value>, Map,
855 typename SmartParameter<Map>::Type>(name, map);
858 /// \brief Add a new edge map reader command for the reader.
860 /// Add a new edge map reader command for the reader.
861 template <typename Reader, typename Map>
862 EdgeSetReader& readEdgeMap(std::string name, Map& map,
863 const Reader& reader = Reader()) {
865 typename Traits::template Reader<typename Map::Value>, Map,
866 typename SmartParameter<Map>::Type>(name, map, reader);
869 template <typename Reader, typename Map>
870 EdgeSetReader& readEdgeMap(std::string name, const Map& map,
871 const Reader& reader = Reader()) {
873 typename Traits::template Reader<typename Map::Value>, Map,
874 typename SmartParameter<Map>::Type>(name, map, reader);
879 template <typename Reader, typename Map, typename MapParameter>
880 EdgeSetReader& _readMap(std::string name, MapParameter map,
881 const Reader& reader = Reader()) {
882 if (readers.find(name) != readers.end()) {
884 msg << "Multiple read rule for edge map: " << name;
885 throw IOParameterError(msg.message());
888 make_pair(name, new MapReader<Item, Map, Reader>(map, reader)));
894 /// \brief Add a new edge map skipper command for the reader.
896 /// Add a new edge map skipper command for the reader.
897 template <typename Reader>
898 EdgeSetReader& skipEdgeMap(std::string name,
899 const Reader& reader = Reader()) {
900 if (readers.find(name) != readers.end()) {
902 msg << "Multiple read rule for edge map: " << name;
903 throw IOParameterError(msg.message());
905 readers.insert(make_pair(name, new SkipReader<Item, Reader>(reader)));
911 /// \brief Gives back true when the SectionReader can process
912 /// the section with the given header line.
914 /// It gives back true when the header line starts with \c \@edgeset,
915 /// and the header line's id and the edgeset's id are the same.
916 virtual bool header(const std::string& line) {
917 std::istringstream ls(line);
920 ls >> command >> name;
921 return command == "@edgeset" && name == id;
924 /// \brief Reader function of the section.
926 /// It reads the content of the section.
927 virtual void read(std::istream& is) {
928 std::vector<ReaderBase<Item>* > index;
932 std::istringstream ls(line);
934 typename MapReaders::iterator it = readers.find(id);
935 if (it != readers.end()) {
936 index.push_back(it->second);
938 index.push_back(&skipper);
940 if (id == "id" && inverter.get() == 0) {
941 inverter.reset(index.back()->getInverter());
942 index.back() = inverter.get();
945 while (getline(is, line)) {
946 std::istringstream ls(line);
947 typename Graph::Node from = nodeIdReader->read(ls);
948 typename Graph::Node to = nodeIdReader->read(ls);
949 typename Graph::Edge edge = graph.addEdge(from, to);
950 for (int i = 0; i < (int)index.size(); ++i) {
951 index[i]->read(ls, edge);
958 /// \brief Returns true if the edgeset can give back the edge by its id.
960 /// Returns true if the edgeset can give back the edge by its id.
961 /// It is possible only if an "id" named map was read.
962 bool isIdReader() const {
963 return inverter.get() != 0;
966 /// \brief Gives back the edge by its id.
968 /// It reads an id from the stream and gives back which edge belongs to
969 /// it. It is possible only if there was read an "id" named map.
970 Item readId(std::istream& is) const {
971 return inverter->read(is);
976 typedef std::map<std::string, ReaderBase<Item>*> MapReaders;
979 typename SmartReference<Graph>::Type graph;
981 SkipReader<Item, DefaultSkipper> skipper;
983 std::auto_ptr<InverterBase<Item> > inverter;
984 std::auto_ptr<IdReaderBase<typename Graph::Node> > nodeIdReader;
987 /// \ingroup io_group
988 /// \brief SectionReader for reading a undirected graph's edgeset.
990 /// The lemon format can store multiple undirected edgesets with several
991 /// maps. The undirected edgeset section's header line is \c \@undiredgeset
992 /// \c undiredgeset_id, but the \c undiredgeset_id may be empty.
994 /// The first line of the section contains the names of the maps separated
995 /// with white spaces. Each next lines describes an edge in the edgeset. The
996 /// line contains the connected nodes' id and the mapped values for each map.
998 /// The section can handle the directed as a syntactical sugar. Two
999 /// undirected edge map describes one directed edge map. This two maps
1000 /// are the forward map and the backward map and the names of this map
1001 /// is near the same just with a prefix \c '+' or \c '-' character
1004 /// If the edgeset contains an \c "id" named map then it will be regarded
1005 /// as id map. This map should contain only unique values and when the
1006 /// \c readId() member will read a value from the given stream it will
1007 /// give back that undiricted edge which is mapped to this value.
1009 /// The undirected edgeset reader needs a node id reader to identify which
1010 /// nodes have to be connected. If a NodeSetReader reads an "id" named map,
1011 /// it will be able to resolve the nodes by ids.
1013 /// \relates LemonReader
1014 template <typename _Graph, typename _Traits = DefaultReaderTraits>
1015 class UndirEdgeSetReader : public CommonSectionReaderBase {
1016 typedef CommonSectionReaderBase Parent;
1019 typedef _Graph Graph;
1020 typedef _Traits Traits;
1021 typedef typename Graph::UndirEdge Item;
1022 typedef typename Traits::Skipper DefaultSkipper;
1024 /// \brief Constructor.
1026 /// Constructor for UndirEdgeSetReader. It creates the UndirEdgeSetReader
1027 /// and attach it into the given LemonReader. The undirected edgeset
1028 /// reader will add the readed undirected edges to the given Graph. It
1029 /// will use the given node id reader to read the source and target
1030 /// nodes of the edges. The reader will read the section only if the
1031 /// \c _id and the \c undiredgset_id are the same.
1032 template <typename NodeIdReader>
1033 UndirEdgeSetReader(LemonReader& _reader,
1034 typename SmartParameter<Graph>::Type _graph,
1035 const NodeIdReader& _nodeIdReader,
1036 const std::string& _id = std::string(),
1037 const DefaultSkipper& _skipper = DefaultSkipper())
1038 : Parent(_reader), graph(_graph), id(_id), skipper(_skipper),
1039 nodeIdReader(new IdReader<typename Graph::Node, NodeIdReader>
1042 /// \brief Destructor.
1044 /// Destructor for UndirEdgeSetReader.
1045 virtual ~UndirEdgeSetReader() {
1046 for (typename MapReaders::iterator it = readers.begin();
1047 it != readers.end(); ++it) {
1053 UndirEdgeSetReader(const UndirEdgeSetReader&);
1054 void operator=(const UndirEdgeSetReader&);
1058 /// \brief Add a new undirected edge map reader command for the reader.
1060 /// Add a new edge undirected map reader command for the reader.
1061 template <typename Map>
1062 UndirEdgeSetReader& readUndirEdgeMap(std::string name, Map& map) {
1064 typename Traits::template Reader<typename Map::Value>, Map,
1065 typename SmartParameter<Map>::Type>(name, map);
1068 template <typename Map>
1069 UndirEdgeSetReader& readUndirEdgeMap(std::string name, const Map& map) {
1071 typename Traits::template Reader<typename Map::Value>, Map,
1072 typename SmartParameter<Map>::Type>(name, map);
1075 /// \brief Add a new undirected edge map reader command for the reader.
1077 /// Add a new edge undirected map reader command for the reader.
1078 template <typename Reader, typename Map>
1079 UndirEdgeSetReader& readUndirEdgeMap(std::string name, Map& map,
1080 const Reader& reader = Reader()) {
1081 return _readMap<Reader, Map, typename SmartParameter<Map>::Type>
1082 (name, map, reader);
1085 template <typename Reader, typename Map>
1086 UndirEdgeSetReader& readUndirEdgeMap(std::string name, const Map& map,
1087 const Reader& reader = Reader()) {
1088 return _readMap<Reader, Map, typename SmartParameter<Map>::Type >
1089 (name, map, reader);
1094 template <typename Reader, typename Map, typename MapParameter>
1095 UndirEdgeSetReader& _readMap(std::string name, MapParameter map,
1096 const Reader& reader = Reader()) {
1097 if (readers.find(name) != readers.end()) {
1099 msg << "Multiple read rule for edge map: " << name;
1100 throw IOParameterError(msg.message());
1103 make_pair(name, new MapReader<Item, Map, Reader>(map, reader)));
1109 /// \brief Add a new undirected edge map skipper command for the reader.
1111 /// Add a new undirected edge map skipper command for the reader.
1112 template <typename Reader>
1113 UndirEdgeSetReader& skipUndirEdgeMap(std::string name,
1114 const Reader& reader = Reader()) {
1115 if (readers.find(name) != readers.end()) {
1117 msg << "Multiple read rule for node map: " << name;
1118 throw IOParameterError(msg.message());
1120 readers.insert(make_pair(name, new SkipReader<Item, Reader>(reader)));
1124 /// \brief Add a new directed edge map reader command for the reader.
1126 /// Add a new directed edge map reader command for the reader.
1127 template <typename Map>
1128 UndirEdgeSetReader& readEdgeMap(std::string name, Map& map) {
1130 typename Traits::template Reader<typename Map::Value>, Map,
1131 typename SmartParameter<Map>::Type>(name, map);
1134 template <typename Map>
1135 UndirEdgeSetReader& readEdgeMap(std::string name, const Map& map) {
1137 typename Traits::template Reader<typename Map::Value>, Map,
1138 typename SmartParameter<Map>::Type>(name, map);
1141 /// \brief Add a new directed edge map reader command for the reader.
1143 /// Add a new directed edge map reader command for the reader.
1144 template <typename Reader, typename Map>
1145 UndirEdgeSetReader& readEdgeMap(std::string name, Map& map,
1146 const Reader& reader = Reader()) {
1147 return _readDirMap<Reader, Map, typename SmartParameter<Map>::Type>
1148 (name, map, reader);
1151 template <typename Reader, typename Map>
1152 UndirEdgeSetReader& readEdgeMap(std::string name, const Map& map,
1153 const Reader& reader = Reader()) {
1154 return _readDirMap<Reader, Map, typename SmartParameter<Map>::Type>
1155 (name, map, reader);
1160 template <typename Reader, typename Map, typename MapParameter>
1161 UndirEdgeSetReader& _readDirMap(std::string name, MapParameter map,
1162 const Reader& reader = Reader()) {
1164 _reader_bits::writeComposeMap(map, forwardMap(graph)), reader);
1166 _reader_bits::writeComposeMap(map, backwardMap(graph)), reader);
1172 /// \brief Add a new directed edge map skipper command for the reader.
1174 /// Add a new directed edge map skipper command for the reader.
1175 template <typename Reader>
1176 UndirEdgeSetReader& skipEdgeMap(std::string name,
1177 const Reader& reader = Reader()) {
1178 skipMap("+" + name, reader);
1179 skipMap("-" + name, reader);
1185 /// \brief Gives back true when the SectionReader can process
1186 /// the section with the given header line.
1188 /// It gives back true when the header line starts with \c \@undiredgeset,
1189 /// and the header line's id and the edgeset's id are the same.
1190 virtual bool header(const std::string& line) {
1191 std::istringstream ls(line);
1192 std::string command;
1194 ls >> command >> name;
1195 return command == "@undiredgeset" && name == id;
1198 /// \brief Reader function of the section.
1200 /// It reads the content of the section.
1201 virtual void read(std::istream& is) {
1202 std::vector<ReaderBase<Item>* > index;
1206 std::istringstream ls(line);
1208 typename MapReaders::iterator it = readers.find(id);
1209 if (it != readers.end()) {
1210 index.push_back(it->second);
1212 index.push_back(&skipper);
1214 if (id == "id" && inverter.get() == 0) {
1215 inverter.reset(index.back()->getInverter());
1216 index.back() = inverter.get();
1219 while (getline(is, line)) {
1220 std::istringstream ls(line);
1221 typename Graph::Node from = nodeIdReader->read(ls);
1222 typename Graph::Node to = nodeIdReader->read(ls);
1223 typename Graph::UndirEdge edge = graph.addEdge(from, to);
1224 for (int i = 0; i < (int)index.size(); ++i) {
1225 index[i]->read(ls, edge);
1232 /// \brief Returns true if the edgeset can give back the edge by its id.
1234 /// Returns true if the edgeset can give back the undirected edge by its
1235 /// id. It is possible only if an "id" named map was read.
1236 bool isIdReader() const {
1237 return inverter.get() != 0;
1240 /// \brief Gives back the undirected edge by its id.
1242 /// It reads an id from the stream and gives back which undirected edge
1243 /// belongs to it. It is possible only if there was read an "id" named map.
1244 Item readId(std::istream& is) const {
1245 return inverter->read(is);
1250 typedef std::map<std::string, ReaderBase<Item>*> MapReaders;
1253 typename SmartReference<Graph>::Type graph;
1255 SkipReader<Item, DefaultSkipper> skipper;
1257 std::auto_ptr<InverterBase<Item> > inverter;
1258 std::auto_ptr<IdReaderBase<typename Graph::Node> > nodeIdReader;
1261 /// \ingroup io_group
1262 /// \brief SectionReader for reading labeled nodes.
1264 /// The nodes section's header line is \c \@nodes \c nodes_id, but the
1265 /// \c nodes_id may be empty.
1267 /// Each line in the section contains the name of the node
1268 /// and then the node id.
1270 /// \relates LemonReader
1271 template <typename _Graph>
1272 class NodeReader : public CommonSectionReaderBase {
1273 typedef CommonSectionReaderBase Parent;
1274 typedef _Graph Graph;
1275 typedef typename Graph::Node Item;
1278 /// \brief Constructor.
1280 /// Constructor for NodeReader. It creates the NodeReader and
1281 /// attach it into the given LemonReader. It will use the given
1282 /// node id reader to give back the nodes. The reader will read the
1283 /// section only if the \c _id and the \c nodes_id are the same.
1284 template <typename _IdReader>
1285 NodeReader(LemonReader& _reader, const _IdReader& _idReader,
1286 const std::string& _id = std::string())
1287 : Parent(_reader), id(_id),
1288 idReader(new IdReader<typename Graph::Node, _IdReader>(_idReader)) {}
1290 /// \brief Destructor.
1292 /// Destructor for NodeReader.
1293 virtual ~NodeReader() {}
1296 NodeReader(const NodeReader&);
1297 void operator=(const NodeReader&);
1301 /// \brief Add a node reader command for the NodeReader.
1303 /// Add a node reader command for the NodeReader.
1304 void readNode(const std::string& name, Item& item) {
1305 if (readers.find(name) != readers.end()) {
1307 msg << "Multiple read rule for node: " << name;
1308 throw IOParameterError(msg.message());
1310 readers.insert(make_pair(name, &item));
1315 /// \brief Gives back true when the SectionReader can process
1316 /// the section with the given header line.
1318 /// It gives back true when the header line start with \c \@nodes,
1319 /// and the header line's id and the reader's id are the same.
1320 virtual bool header(const std::string& line) {
1321 std::istringstream ls(line);
1322 std::string command;
1324 ls >> command >> name;
1325 return command == "@nodes" && name == id;
1328 /// \brief Reader function of the section.
1330 /// It reads the content of the section.
1331 virtual void read(std::istream& is) {
1333 while (getline(is, line)) {
1334 std::istringstream ls(line);
1337 typename ItemReaders::iterator it = readers.find(id);
1338 if (it != readers.end()) {
1339 *(it->second) = idReader->read(ls);
1348 typedef std::map<std::string, Item*> ItemReaders;
1349 ItemReaders readers;
1350 std::auto_ptr<IdReaderBase<Item> > idReader;
1353 /// \ingroup io_group
1354 /// \brief SectionReader for reading labeled edges.
1356 /// The edges section's header line is \c \@edges \c edges_id, but the
1357 /// \c edges_id may be empty.
1359 /// Each line in the section contains the name of the edge
1360 /// and then the edge id.
1362 /// \relates LemonReader
1363 template <typename _Graph>
1364 class EdgeReader : public CommonSectionReaderBase {
1365 typedef CommonSectionReaderBase Parent;
1366 typedef _Graph Graph;
1367 typedef typename Graph::Edge Item;
1370 /// \brief Constructor.
1372 /// Constructor for EdgeReader. It creates the EdgeReader and
1373 /// attach it into the given LemonReader. It will use the given
1374 /// edge id reader to give back the edges. The reader will read the
1375 /// section only if the \c _id and the \c edges_id are the same.
1376 template <typename _IdReader>
1377 EdgeReader(LemonReader& _reader, const _IdReader& _idReader,
1378 const std::string& _id = std::string())
1379 : Parent(_reader), id(_id),
1380 idReader(new IdReader<typename Graph::Edge, _IdReader>(_idReader)) {}
1382 /// \brief Destructor.
1384 /// Destructor for EdgeReader.
1385 virtual ~EdgeReader() {}
1387 EdgeReader(const EdgeReader&);
1388 void operator=(const EdgeReader&);
1392 /// \brief Add an edge reader command for the EdgeReader.
1394 /// Add an edge reader command for the EdgeReader.
1395 void readEdge(const std::string& name, Item& item) {
1396 if (readers.find(name) != readers.end()) {
1398 msg << "Multiple read rule for edge: " << name;
1399 throw IOParameterError(msg.message());
1401 readers.insert(make_pair(name, &item));
1406 /// \brief Gives back true when the SectionReader can process
1407 /// the section with the given header line.
1409 /// It gives back true when the header line start with \c \@edges,
1410 /// and the header line's id and the reader's id are the same.
1411 virtual bool header(const std::string& line) {
1412 std::istringstream ls(line);
1413 std::string command;
1415 ls >> command >> name;
1416 return command == "@edges" && name == id;
1419 /// \brief Reader function of the section.
1421 /// It reads the content of the section.
1422 virtual void read(std::istream& is) {
1424 while (getline(is, line)) {
1425 std::istringstream ls(line);
1428 typename ItemReaders::iterator it = readers.find(id);
1429 if (it != readers.end()) {
1430 *(it->second) = idReader->read(ls);
1439 typedef std::map<std::string, Item*> ItemReaders;
1440 ItemReaders readers;
1441 std::auto_ptr<IdReaderBase<Item> > idReader;
1444 /// \ingroup io_group
1445 /// \brief SectionReader for reading labeled undirected edges.
1447 /// The undirected edges section's header line is \c \@undiredges
1448 /// \c undiredges_id, but the \c undiredges_id may be empty.
1450 /// Each line in the section contains the name of the undirected edge
1451 /// and then the undirected edge id.
1453 /// \relates LemonReader
1454 template <typename _Graph>
1455 class UndirEdgeReader : public CommonSectionReaderBase {
1456 typedef CommonSectionReaderBase Parent;
1457 typedef _Graph Graph;
1458 typedef typename Graph::UndirEdge Item;
1461 /// \brief Constructor.
1463 /// Constructor for UndirEdgeReader. It creates the UndirEdgeReader and
1464 /// attach it into the given LemonReader. It will use the given
1465 /// undirected edge id reader to give back the edges. The reader will
1466 /// read the section only if the \c _id and the \c undiredges_id are
1468 template <typename _IdReader>
1469 UndirEdgeReader(LemonReader& _reader, const _IdReader& _idReader,
1470 const std::string& _id = std::string())
1471 : Parent(_reader), id(_id),
1472 idReader(new IdReader<typename Graph::UndirEdge, _IdReader>(_idReader))
1475 /// \brief Destructor.
1477 /// Destructor for UndirEdgeReader.
1478 virtual ~UndirEdgeReader() {}
1480 UndirEdgeReader(const UndirEdgeReader&);
1481 void operator=(const UndirEdgeReader&);
1485 /// \brief Add an undirected edge reader command for the UndirEdgeReader.
1487 /// Add an undirected edge reader command for the UndirEdgeReader.
1488 void readUndirEdge(const std::string& name, Item& item) {
1489 if (readers.find(name) != readers.end()) {
1491 msg << "Multiple read rule for edge: " << name;
1492 throw IOParameterError(msg.message());
1494 readers.insert(make_pair(name, &item));
1499 /// \brief Gives back true when the SectionReader can process
1500 /// the section with the given header line.
1502 /// It gives back true when the header line start with \c \@edges,
1503 /// and the header line's id and the reader's id are the same.
1504 virtual bool header(const std::string& line) {
1505 std::istringstream ls(line);
1506 std::string command;
1508 ls >> command >> name;
1509 return command == "@edges" && name == id;
1512 /// \brief Reader function of the section.
1514 /// It reads the content of the section.
1515 virtual void read(std::istream& is) {
1517 while (getline(is, line)) {
1518 std::istringstream ls(line);
1521 typename ItemReaders::iterator it = readers.find(id);
1522 if (it != readers.end()) {
1523 *(it->second) = idReader->read(ls);
1532 typedef std::map<std::string, Item*> ItemReaders;
1533 ItemReaders readers;
1534 std::auto_ptr<IdReaderBase<Item> > idReader;
1537 /// \ingroup io_group
1538 /// \brief SectionReader for attributes.
1540 /// The lemon format can store multiple attribute set. Each set has
1541 /// the header line \c \@attributes \c attributeset_id, but the
1542 /// attributeset_id may be empty.
1544 /// The attributeset section contains several lines. Each of them starts
1545 /// with an attribute and then a the value for the id.
1547 /// \relates LemonReader
1548 template <typename _Traits = DefaultReaderTraits>
1549 class AttributeReader : public CommonSectionReaderBase {
1550 typedef CommonSectionReaderBase Parent;
1551 typedef _Traits Traits;
1553 /// \brief Constructor.
1555 /// Constructor for AttributeReader. It creates the AttributeReader and
1556 /// attach it into the given LemonReader. The reader process a section
1557 /// only if the \c section_id and the \c _id are the same.
1558 AttributeReader(LemonReader& _reader,
1559 const std::string& _id = std::string())
1560 : Parent(_reader), id(_id) {}
1562 /// \brief Destructor.
1564 /// Destructor for AttributeReader.
1565 virtual ~AttributeReader() {
1566 for (typename Readers::iterator it = readers.begin();
1567 it != readers.end(); ++it) {
1573 AttributeReader(const AttributeReader&);
1574 void operator=(AttributeReader&);
1577 /// \brief Add an attribute reader command for the reader.
1579 /// Add an attribute reader command for the reader.
1580 template <typename Value>
1581 AttributeReader& readAttribute(const std::string& id, Value& value) {
1582 return readAttribute<typename Traits::template Reader<Value> >
1586 /// \brief Add an attribute reader command for the reader.
1588 /// Add an attribute reader command for the reader.
1589 template <typename Reader, typename Value>
1590 AttributeReader& readAttribute(const std::string& name, Value& value,
1591 const Reader& reader = Reader()) {
1592 if (readers.find(name) != readers.end()) {
1594 msg << "Multiple read rule for attribute: " << name;
1595 throw IOParameterError(msg.message());
1597 readers.insert(make_pair(name, new ValueReader<Value, Reader>
1604 /// \brief Gives back true when the SectionReader can process
1605 /// the section with the given header line.
1607 /// It gives back true when the header line start with \c \@attributes,
1608 /// and the header line's id and the attributeset's id are the same.
1609 bool header(const std::string& line) {
1610 std::istringstream ls(line);
1611 std::string command;
1613 ls >> command >> name;
1614 return command == "@attributes" && name == id;
1617 /// \brief Reader function of the section.
1619 /// It reads the content of the section.
1620 void read(std::istream& is) {
1622 while (getline(is, line)) {
1623 std::istringstream ls(line);
1626 typename Readers::iterator it = readers.find(id);
1627 if (it != readers.end()) {
1628 it->second->read(ls);
1636 typedef std::map<std::string, ValueReaderBase*> Readers;
1640 /// \ingroup io_group
1641 /// \brief SectionReader for retrieve what is in the file.
1643 /// SectionReader for retrieve what is in the file. If you want
1644 /// to know which sections, maps and items are in the file
1645 /// use the next code:
1647 /// LemonReader reader("input.lgf");
1648 /// ContentReader content(reader);
1651 class ContentReader : public LemonReader::SectionReader {
1652 typedef LemonReader::SectionReader Parent;
1654 /// \brief Constructor.
1657 ContentReader(LemonReader& _reader) : Parent(_reader) {}
1659 /// \brief Desctructor.
1662 virtual ~ContentReader() {}
1664 /// \brief Gives back how many nodesets are in the file.
1666 /// Gives back how many nodesets are in the file.
1667 int nodeSetNum() const {
1668 return nodesets.size();
1671 /// \brief Gives back the name of nodeset on the indiced position.
1673 /// Gives back the name of nodeset on the indiced position.
1674 std::string nodeSetName(int index) const {
1675 return nodesets[index].name;
1678 /// \brief Gives back the map names of nodeset on the indiced position.
1680 /// Gives back the map names of nodeset on the indiced position.
1681 const std::vector<std::string>& nodeSetMaps(int index) const {
1682 return nodesets[index].items;
1685 /// \brief Gives back how many edgesets are in the file.
1687 /// Gives back how many edgesets are in the file.
1688 int edgeSetNum() const {
1689 return edgesets.size();
1692 /// \brief Gives back the name of edgeset on the indiced position.
1694 /// Gives back the name of edgeset on the indiced position.
1695 std::string edgeSetName(int index) const {
1696 return edgesets[index].name;
1699 /// \brief Gives back the map names of edgeset on the indiced position.
1701 /// Gives back the map names of edgeset on the indiced position.
1702 const std::vector<std::string>& edgeSetMaps(int index) const {
1703 return edgesets[index].items;
1706 /// \brief Gives back how many undirected edgesets are in the file.
1708 /// Gives back how many undirected edgesets are in the file.
1709 int undirEdgeSetNum() const {
1710 return undiredgesets.size();
1713 /// \brief Gives back the name of undirected edgeset on the indiced
1716 /// Gives back the name of undirected edgeset on the indiced position.
1717 std::string undirEdgeSetName(int index) const {
1718 return undiredgesets[index].name;
1721 /// \brief Gives back the map names of undirected edgeset on the indiced
1724 /// Gives back the map names of undirected edgeset on the indiced position.
1725 const std::vector<std::string>& undirEdgeSetMaps(int index) const {
1726 return undiredgesets[index].items;
1729 /// \brief Gives back how many labeled nodes section are in the file.
1731 /// Gives back how many labeled nodes section are in the file.
1732 int nodesNum() const {
1733 return nodes.size();
1736 /// \brief Gives back the name of labeled nodes section on the indiced
1739 /// Gives back the name of labeled nodes section on the indiced position.
1740 std::string nodesName(int index) const {
1741 return nodes[index].name;
1744 /// \brief Gives back the names of the labeled nodes in the indiced
1747 /// Gives back the names of the labeled nodes in the indiced section.
1748 const std::vector<std::string>& nodesItems(int index) const {
1749 return nodes[index].items;
1752 /// \brief Gives back how many labeled edges section are in the file.
1754 /// Gives back how many labeled edges section are in the file.
1755 int edgesNum() const {
1756 return edges.size();
1759 /// \brief Gives back the name of labeled edges section on the indiced
1762 /// Gives back the name of labeled edges section on the indiced position.
1763 std::string edgesName(int index) const {
1764 return edges[index].name;
1767 /// \brief Gives back the names of the labeled edges in the indiced
1770 /// Gives back the names of the labeled edges in the indiced section.
1771 const std::vector<std::string>& edgesItems(int index) const {
1772 return edges[index].items;
1775 /// \brief Gives back how many labeled undirected edges section are
1778 /// Gives back how many labeled undirected edges section are in the file.
1779 int undirEdgesNum() const {
1780 return undiredges.size();
1783 /// \brief Gives back the name of labeled undirected edges section
1784 /// on the indiced position.
1786 /// Gives back the name of labeled undirected edges section on the
1787 /// indiced position.
1788 std::string undirEdgesName(int index) const {
1789 return undiredges[index].name;
1792 /// \brief Gives back the names of the labeled undirected edges in
1793 /// the indiced section.
1795 /// Gives back the names of the labeled undirected edges in the
1796 /// indiced section.
1797 const std::vector<std::string>& undirEdgesItems(int index) const {
1798 return undiredges[index].items;
1802 /// \brief Gives back how many attributes section are in the file.
1804 /// Gives back how many attributes section are in the file.
1805 int attributesNum() const {
1806 return attributes.size();
1809 /// \brief Gives back the name of attributes section on the indiced
1812 /// Gives back the name of attributes section on the indiced position.
1813 std::string attributesName(int index) const {
1814 return attributes[index].name;
1817 /// \brief Gives back the names of the attributes in the indiced section.
1819 /// Gives back the names of the attributes in the indiced section.
1820 const std::vector<std::string>& attributesItems(int index) const {
1821 return attributes[index].items;
1824 const std::vector<std::string>& otherSections() const {
1830 /// \brief Gives back true when the SectionReader can process
1831 /// the section with the given header line.
1833 /// It gives back true when the section is common section.
1834 bool header(const std::string& line) {
1835 std::istringstream ls(line);
1836 std::string command, name;
1837 ls >> command >> name;
1838 if (command == "@nodeset") {
1840 nodesets.push_back(SectionInfo(name));
1841 } else if (command == "@edgeset") {
1843 edgesets.push_back(SectionInfo(name));
1844 } else if (command == "@undiredgeset") {
1846 undiredgesets.push_back(SectionInfo(name));
1847 } else if (command == "@nodes") {
1849 nodes.push_back(SectionInfo(name));
1850 } else if (command == "@edges") {
1852 edges.push_back(SectionInfo(name));
1853 } else if (command == "@undiredges") {
1855 undiredges.push_back(SectionInfo(name));
1856 } else if (command == "@attributes") {
1858 attributes.push_back(SectionInfo(name));
1860 sections.push_back(line);
1866 /// \brief Retrieve the items from various sections.
1868 /// Retrieve the items from various sections.
1869 void read(std::istream& is) {
1870 if (current == "@nodeset") {
1871 readMapNames(is, nodesets.back().items);
1872 } else if (current == "@edgeset") {
1873 readMapNames(is, edgesets.back().items);
1874 } else if (current == "@undiredgeset") {
1875 readMapNames(is, undiredgesets.back().items);
1876 } else if (current == "@nodes") {
1877 readItemNames(is, nodes.back().items);
1878 } else if (current == "@edges") {
1879 readItemNames(is, edges.back().items);
1880 } else if (current == "@undiredges") {
1881 readItemNames(is, undiredges.back().items);
1882 } else if (current == "@attributes") {
1883 readItemNames(is, attributes.back().items);
1889 void readMapNames(std::istream& is, std::vector<std::string>& maps) {
1890 std::string line, id;
1891 std::getline(is, line);
1892 std::istringstream ls(line);
1896 while (getline(is, line));
1899 void readItemNames(std::istream& is, std::vector<std::string>& maps) {
1900 std::string line, id;
1901 while (std::getline(is, line)) {
1902 std::istringstream ls(line);
1908 struct SectionInfo {
1910 std::vector<std::string> items;
1912 SectionInfo(const std::string& _name) : name(_name) {}
1915 std::vector<SectionInfo> nodesets;
1916 std::vector<SectionInfo> edgesets;
1917 std::vector<SectionInfo> undiredgesets;
1919 std::vector<SectionInfo> nodes;
1920 std::vector<SectionInfo> edges;
1921 std::vector<SectionInfo> undiredges;
1923 std::vector<SectionInfo> attributes;
1925 std::vector<std::string> sections;
1927 std::string current;