Bug fix.
I programmed to much templates.
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 lines and it may contain comments
103 /// started with a \c # character to the end of the line.
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 lines
112 /// and comments 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 {
141 char_type small_buf[1];
151 skip_state_type skip_state;
154 char_type* base() { return _base; }
156 char_type* eptr() { return _eptr; }
158 int blen() { return _eptr - _base; }
160 void setb(char_type* buf, int len) {
165 virtual std::streambuf* setbuf(char *buf, int len) {
166 if (base()) return 0;
167 if (buf != 0 && len >= (int)sizeof(small_buf)) {
170 setb(small_buf, sizeof(small_buf));
176 bool put_char(char c) {
177 switch (skip_state) {
181 skip_state = after_endl;
184 skip_state = after_comment;
192 skip_state = after_endl;
204 skip_state = empty_line;
208 skip_state = no_skip;
218 skip_state = after_endl;
227 virtual int underflow() {
229 if (_is.read(&c, 1)) {
238 for (ptr = base(); ptr != eptr(); ++ptr) {
239 if (_is.read(&c, 1)) {
240 if (c == '\n') ++_num;
244 if (skip_state == after_endl && c == '@') {
254 setg(base(), base(), ptr);
265 /// \brief Abstract base class for reading a section.
267 /// This class has an \c header() member function what get a
268 /// header line string and decides if it want to process the next
269 /// section. Several SectionReaders can be attached to an LemonReader
270 /// and the first attached what can process the section will be used.
271 /// Its \c read() member will called with a stream contains the section.
272 /// From this stream the empty lines and comments are filtered out.
273 class SectionReader {
274 friend class LemonReader;
276 /// \brief Constructor for SectionReader.
278 /// Constructor for SectionReader. It attach this reader to
279 /// the given LemonReader.
280 SectionReader(LemonReader& reader) {
281 reader.attach(*this);
284 /// \brief Gives back true when the SectionReader can process
285 /// the section with the given header line.
287 /// It gives back true when the SectionReader can process
288 /// the section with the given header line.
289 virtual bool header(const std::string& line) = 0;
291 /// \brief Reader function of the section.
293 /// It reads the content of the section.
294 virtual void read(std::istream& is) = 0;
297 /// \brief Constructor for LemonReader.
299 /// Constructor for LemonReader which reads from the given stream.
300 LemonReader(std::istream& _is)
301 : is(&_is), own_is(false) {}
303 /// \brief Constructor for LemonReader.
305 /// Constructor for LemonReader which reads from the given file.
306 LemonReader(const std::string& filename)
307 : is(0), own_is(true) {
308 is = new std::ifstream(filename.c_str());
311 /// \brief Desctructor for LemonReader.
313 /// Desctructor for LemonReader.
321 LemonReader(const LemonReader&);
322 void operator=(const LemonReader&);
324 void attach(SectionReader& reader) {
325 readers.push_back(&reader);
329 /// \brief Executes the LemonReader.
331 /// It executes the LemonReader.
336 while ((++line_num, getline(*is, line)) && line.find("@end") != 0) {
337 SectionReaders::iterator it;
338 for (it = readers.begin(); it != readers.end(); ++it) {
339 if ((*it)->header(line)) {
341 FilterStreamBuf buffer(*is, line_num);
342 buffer.pubsetbuf(buf, sizeof(buf));
343 std::istream is(&buffer);
349 } catch (DataFormatError& error) {
350 error.line(line_num);
361 typedef std::vector<SectionReader*> SectionReaders;
362 SectionReaders readers;
366 /// \brief Helper class for implementing the common SectionReaders.
368 /// Helper class for implementing the common SectionReaders.
369 class CommonSectionReaderBase : public LemonReader::SectionReader {
370 typedef LemonReader::SectionReader Parent;
373 /// \brief Constructor for CommonSectionReaderBase.
375 /// Constructor for CommonSectionReaderBase. It attach this reader to
376 /// the given LemonReader.
377 CommonSectionReaderBase(LemonReader& _reader)
380 template <typename _Item>
383 template <typename _Item>
384 class InverterBase : public ReaderBase<_Item> {
387 virtual void read(std::istream&, const Item&) = 0;
388 virtual Item read(std::istream&) const = 0;
390 virtual InverterBase<_Item>* getInverter() {
395 template <typename _Item, typename _Map, typename _Reader>
396 class MapReaderInverter : public InverterBase<_Item> {
399 typedef _Reader Reader;
400 typedef typename Reader::Value Value;
402 typedef std::map<Value, Item, _reader_bits::Less<Value> > Inverse;
404 typename SmartReference<Map>::Type map;
408 MapReaderInverter(typename SmartParameter<Map>::Type _map,
409 const Reader& _reader)
410 : map(_map), reader(_reader) {}
412 virtual ~MapReaderInverter() {}
414 virtual void read(std::istream& is, const Item& item) {
416 reader.read(is, value);
417 map.set(item, value);
418 typename Inverse::iterator it = inverse.find(value);
419 if (it == inverse.end()) {
420 inverse.insert(std::make_pair(value, item));
422 throw DataFormatError("Multiple ID occurence");
426 virtual Item read(std::istream& is) const {
428 reader.read(is, value);
429 typename Inverse::const_iterator it = inverse.find(value);
430 if (it != inverse.end()) {
433 throw DataFormatError("Invalid ID error");
438 template <typename _Item, typename _Reader>
439 class SkipReaderInverter : public InverterBase<_Item> {
442 typedef _Reader Reader;
443 typedef typename Reader::Value Value;
444 typedef std::map<Value, Item, _reader_bits::Less<Value> > Inverse;
448 SkipReaderInverter(const Reader& _reader)
451 virtual ~SkipReaderInverter() {}
453 virtual void read(std::istream& is, const Item& item) {
455 reader.read(is, value);
456 typename Inverse::iterator it = inverse.find(value);
457 if (it == inverse.end()) {
458 inverse.insert(std::make_pair(value, item));
460 throw DataFormatError("Multiple ID occurence error");
464 virtual Item read(std::istream& is) const {
466 reader.read(is, value);
467 typename Inverse::const_iterator it = inverse.find(value);
468 if (it != inverse.end()) {
471 throw DataFormatError("Invalid ID error");
479 template <typename _Item>
484 virtual ~ReaderBase() {}
486 virtual void read(std::istream& is, const Item& item) = 0;
487 virtual InverterBase<_Item>* getInverter() = 0;
490 template <typename _Item, typename _Map, typename _Reader>
491 class MapReader : public ReaderBase<_Item> {
494 typedef _Reader Reader;
495 typedef typename Reader::Value Value;
498 typename SmartReference<Map>::Type map;
501 MapReader(typename SmartParameter<Map>::Type _map,
502 const Reader& _reader)
503 : map(_map), reader(_reader) {}
505 virtual ~MapReader() {}
507 virtual void read(std::istream& is, const Item& item) {
509 reader.read(is, value);
510 map.set(item, value);
513 virtual InverterBase<_Item>* getInverter() {
514 return new MapReaderInverter<Item, Map, Reader>(map, reader);
519 template <typename _Item, typename _Reader>
520 class SkipReader : public ReaderBase<_Item> {
522 typedef _Reader Reader;
523 typedef typename Reader::Value Value;
527 SkipReader(const Reader& _reader) : reader(_reader) {}
529 virtual ~SkipReader() {}
531 virtual void read(std::istream& is, const Item&) {
533 reader.read(is, value);
536 virtual InverterBase<Item>* getInverter() {
537 return new SkipReaderInverter<Item, Reader>(reader);
541 template <typename _Item>
545 virtual Item read(std::istream& is) const = 0;
548 template <typename _Item, typename _BoxedIdReader>
549 class IdReader : public IdReaderBase<_Item> {
552 typedef _BoxedIdReader BoxedIdReader;
554 const BoxedIdReader& boxedIdReader;
556 IdReader(const BoxedIdReader& _boxedIdReader)
557 : boxedIdReader(_boxedIdReader) {}
559 virtual Item read(std::istream& is) const {
560 return boxedIdReader.readId(is);
564 class ValueReaderBase {
566 virtual void read(std::istream&) {};
569 template <typename _Value, typename _Reader>
570 class ValueReader : public ValueReaderBase {
572 typedef _Value Value;
573 typedef _Reader Reader;
575 ValueReader(Value& _value, const Reader& _reader)
576 : value(_value), reader(_reader) {}
578 virtual void read(std::istream& is) {
579 reader.read(is, value);
588 /// \ingroup io_group
589 /// \brief SectionReader for reading a graph's nodeset.
591 /// The lemon format can store multiple graph nodesets with several maps.
592 /// The nodeset section's header line is \c \@nodeset \c nodeset_id, but the
593 /// \c nodeset_id may be empty.
595 /// The first line of the section contains the names of the maps separated
596 /// with white spaces. Each next lines describes a node in the nodeset, and
597 /// contains the mapped values for each map.
599 /// If the nodeset contains an \c "id" named map then it will be regarded
600 /// as id map. This map should contain only unique values and when the
601 /// \c readId() member will read a value from the given stream it will
602 /// give back that node which is mapped to this value.
604 /// \relates LemonReader
605 template <typename _Graph, typename _Traits = DefaultReaderTraits>
606 class NodeSetReader : public CommonSectionReaderBase {
607 typedef CommonSectionReaderBase Parent;
610 typedef _Graph Graph;
611 typedef _Traits Traits;
612 typedef typename Graph::Node Item;
613 typedef typename Traits::Skipper DefaultSkipper;
615 /// \brief Constructor.
617 /// Constructor for NodeSetReader. It creates the NodeSetReader and
618 /// attach it into the given LemonReader. The nodeset reader will
619 /// add the readed nodes to the given Graph. The reader will read
620 /// the section when the \c section_id and the \c _id are the same.
621 NodeSetReader(LemonReader& _reader,
622 typename SmartParameter<Graph>::Type _graph,
623 const std::string& _id = std::string(),
624 const DefaultSkipper& _skipper = DefaultSkipper())
625 : Parent(_reader), graph(_graph), id(_id), skipper(_skipper) {}
628 /// \brief Destructor.
630 /// Destructor for NodeSetReader.
631 virtual ~NodeSetReader() {
632 for (typename MapReaders::iterator it = readers.begin();
633 it != readers.end(); ++it) {
639 NodeSetReader(const NodeSetReader&);
640 void operator=(const NodeSetReader&);
644 /// \brief Add a new node map reader command for the reader.
646 /// Add a new node map reader command for the reader.
647 template <typename Map>
648 NodeSetReader& readNodeMap(std::string name, Map& map) {
650 typename Traits::template Reader<typename Map::Value>, Map,
651 typename SmartParameter<Map>::Type>(name, map);
654 template <typename Map>
655 NodeSetReader& readNodeMap(std::string name, const Map& map) {
657 typename Traits::template Reader<typename Map::Value>, Map,
658 typename SmartParameter<Map>::Type>(name, map);
661 /// \brief Add a new node map reader command for the reader.
663 /// Add a new node map reader command for the reader.
664 template <typename Reader, typename Map>
665 NodeSetReader& readNodeMap(std::string name, Map& map,
666 const Reader& reader = Reader()) {
668 typename Traits::template Reader<typename Map::Value>, Map,
669 typename SmartParameter<Map>::Type>(name, map, reader);
672 template <typename Reader, typename Map>
673 NodeSetReader& readNodeMap(std::string name, const Map& map,
674 const Reader& reader = Reader()) {
676 typename Traits::template Reader<typename Map::Value>, Map,
677 typename SmartParameter<Map>::Type>(name, map, reader);
682 template <typename Reader, typename Map, typename MapParameter>
683 NodeSetReader& _readMap(std::string name, MapParameter map,
684 const Reader& reader = Reader()) {
685 if (readers.find(name) != readers.end()) {
687 msg << "Multiple read rule for node map: " << name;
688 throw IOParameterError(msg.message());
691 make_pair(name, new MapReader<Item, Map, Reader>(map, reader)));
697 /// \brief Add a new node map skipper command for the reader.
699 /// Add a new node map skipper command for the reader.
700 template <typename Reader>
701 NodeSetReader& skipNodeMap(std::string name,
702 const Reader& reader = Reader()) {
703 if (readers.find(name) != readers.end()) {
705 msg << "Multiple read rule for node map: " << name;
706 throw IOParameterError(msg.message());
708 readers.insert(make_pair(name, new SkipReader<Item, Reader>(reader)));
714 /// \brief Gives back true when the SectionReader can process
715 /// the section with the given header line.
717 /// It gives back true when the header line starts with \c \@nodeset,
718 /// and the header line's id and the nodeset's id are the same.
719 virtual bool header(const std::string& line) {
720 std::istringstream ls(line);
723 ls >> command >> name;
724 return command == "@nodeset" && name == id;
727 /// \brief Reader function of the section.
729 /// It reads the content of the section.
730 virtual void read(std::istream& is) {
731 std::vector<ReaderBase<Item>* > index;
735 std::istringstream ls(line);
737 typename MapReaders::iterator it = readers.find(id);
738 if (it != readers.end()) {
739 index.push_back(it->second);
741 index.push_back(&skipper);
743 if (id == "id" && inverter.get() == 0) {
744 inverter.reset(index.back()->getInverter());
745 index.back() = inverter.get();
748 while (getline(is, line)) {
749 typename Graph::Node node = graph.addNode();
750 std::istringstream ls(line);
751 for (int i = 0; i < (int)index.size(); ++i) {
752 index[i]->read(ls, node);
759 /// \brief Returns true if the nodeset can give back the node by its id.
761 /// Returns true if the nodeset can give back the node by its id.
762 /// It is possible only if an "id" named map was read.
763 bool isIdReader() const {
764 return inverter.get() != 0;
767 /// \brief Gives back the node by its id.
769 /// It reads an id from the stream and gives back which node belongs to
770 /// it. It is possible only if there was read an "id" named map.
771 Item readId(std::istream& is) const {
772 return inverter->read(is);
777 typedef std::map<std::string, ReaderBase<Item>*> MapReaders;
780 typename SmartReference<Graph>::Type graph;
782 SkipReader<Item, DefaultSkipper> skipper;
784 std::auto_ptr<InverterBase<Item> > inverter;
787 /// \ingroup io_group
788 /// \brief SectionReader for reading a graph's edgeset.
790 /// The lemon format can store multiple graph edgesets with several maps.
791 /// The edgeset section's header line is \c \@edgeset \c edgeset_id, but the
792 /// \c edgeset_id may be empty.
794 /// The first line of the section contains the names of the maps separated
795 /// with white spaces. Each next lines describes an edge in the edgeset. The
796 /// line contains the source and the target nodes' id and the mapped
797 /// values for each map.
799 /// If the edgeset contains an \c "id" named map then it will be regarded
800 /// as id map. This map should contain only unique values and when the
801 /// \c readId() member will read a value from the given stream it will
802 /// give back that edge which is mapped to this value.
804 /// The edgeset reader needs a node id reader to identify which nodes
805 /// have to be connected. If a NodeSetReader reads an "id" named map,
806 /// it will be able to resolve the nodes by ids.
808 /// \relates LemonReader
809 template <typename _Graph, typename _Traits = DefaultReaderTraits>
810 class EdgeSetReader : public CommonSectionReaderBase {
811 typedef CommonSectionReaderBase Parent;
814 typedef _Graph Graph;
815 typedef _Traits Traits;
816 typedef typename Graph::Edge Item;
817 typedef typename Traits::Skipper DefaultSkipper;
819 /// \brief Constructor.
821 /// Constructor for EdgeSetReader. It creates the EdgeSetReader and
822 /// attach it into the given LemonReader. The edgeset reader will
823 /// add the readed edges to the given Graph. It will use the given
824 /// node id reader to read the source and target nodes of the edges.
825 /// The reader will read the section only if the \c _id and the
826 /// \c edgset_id are the same.
827 template <typename NodeIdReader>
828 EdgeSetReader(LemonReader& _reader,
829 typename SmartParameter<Graph>::Type _graph,
830 const NodeIdReader& _nodeIdReader,
831 const std::string& _id = std::string(),
832 const DefaultSkipper& _skipper = DefaultSkipper())
833 : Parent(_reader), graph(_graph), id(_id), skipper(_skipper),
834 nodeIdReader(new IdReader<typename Graph::Node, NodeIdReader>
837 /// \brief Destructor.
839 /// Destructor for EdgeSetReader.
840 virtual ~EdgeSetReader() {
841 for (typename MapReaders::iterator it = readers.begin();
842 it != readers.end(); ++it) {
848 EdgeSetReader(const EdgeSetReader&);
849 void operator=(const EdgeSetReader&);
853 /// \brief Add a new edge map reader command for the reader.
855 /// Add a new edge map reader command for the reader.
856 template <typename Map>
857 EdgeSetReader& readEdgeMap(std::string name, Map& map) {
859 typename Traits::template Reader<typename Map::Value>, Map,
860 typename SmartParameter<Map>::Type>(name, map);
863 template <typename Map>
864 EdgeSetReader& readEdgeMap(std::string name, const Map& map) {
866 typename Traits::template Reader<typename Map::Value>, Map,
867 typename SmartParameter<Map>::Type>(name, map);
870 /// \brief Add a new edge map reader command for the reader.
872 /// Add a new edge map reader command for the reader.
873 template <typename Reader, typename Map>
874 EdgeSetReader& readEdgeMap(std::string name, Map& map,
875 const Reader& reader = Reader()) {
877 typename Traits::template Reader<typename Map::Value>, Map,
878 typename SmartParameter<Map>::Type>(name, map, reader);
881 template <typename Reader, typename Map>
882 EdgeSetReader& readEdgeMap(std::string name, const Map& map,
883 const Reader& reader = Reader()) {
885 typename Traits::template Reader<typename Map::Value>, Map,
886 typename SmartParameter<Map>::Type>(name, map, reader);
891 template <typename Reader, typename Map, typename MapParameter>
892 EdgeSetReader& _readMap(std::string name, MapParameter map,
893 const Reader& reader = Reader()) {
894 if (readers.find(name) != readers.end()) {
896 msg << "Multiple read rule for edge map: " << name;
897 throw IOParameterError(msg.message());
900 make_pair(name, new MapReader<Item, Map, Reader>(map, reader)));
906 /// \brief Add a new edge map skipper command for the reader.
908 /// Add a new edge map skipper command for the reader.
909 template <typename Reader>
910 EdgeSetReader& skipEdgeMap(std::string name,
911 const Reader& reader = Reader()) {
912 if (readers.find(name) != readers.end()) {
914 msg << "Multiple read rule for edge map: " << name;
915 throw IOParameterError(msg.message());
917 readers.insert(make_pair(name, new SkipReader<Item, Reader>(reader)));
923 /// \brief Gives back true when the SectionReader can process
924 /// the section with the given header line.
926 /// It gives back true when the header line starts with \c \@edgeset,
927 /// and the header line's id and the edgeset's id are the same.
928 virtual bool header(const std::string& line) {
929 std::istringstream ls(line);
932 ls >> command >> name;
933 return command == "@edgeset" && name == id;
936 /// \brief Reader function of the section.
938 /// It reads the content of the section.
939 virtual void read(std::istream& is) {
940 std::vector<ReaderBase<Item>* > index;
944 std::istringstream ls(line);
946 typename MapReaders::iterator it = readers.find(id);
947 if (it != readers.end()) {
948 index.push_back(it->second);
950 index.push_back(&skipper);
952 if (id == "id" && inverter.get() == 0) {
953 inverter.reset(index.back()->getInverter());
954 index.back() = inverter.get();
957 while (getline(is, line)) {
958 std::istringstream ls(line);
959 typename Graph::Node from = nodeIdReader->read(ls);
960 typename Graph::Node to = nodeIdReader->read(ls);
961 typename Graph::Edge edge = graph.addEdge(from, to);
962 for (int i = 0; i < (int)index.size(); ++i) {
963 index[i]->read(ls, edge);
970 /// \brief Returns true if the edgeset can give back the edge by its id.
972 /// Returns true if the edgeset can give back the edge by its id.
973 /// It is possible only if an "id" named map was read.
974 bool isIdReader() const {
975 return inverter.get() != 0;
978 /// \brief Gives back the edge by its id.
980 /// It reads an id from the stream and gives back which edge belongs to
981 /// it. It is possible only if there was read an "id" named map.
982 Item readId(std::istream& is) const {
983 return inverter->read(is);
988 typedef std::map<std::string, ReaderBase<Item>*> MapReaders;
991 typename SmartReference<Graph>::Type graph;
993 SkipReader<Item, DefaultSkipper> skipper;
995 std::auto_ptr<InverterBase<Item> > inverter;
996 std::auto_ptr<IdReaderBase<typename Graph::Node> > nodeIdReader;
999 /// \ingroup io_group
1000 /// \brief SectionReader for reading a undirected graph's edgeset.
1002 /// The lemon format can store multiple undirected edgesets with several
1003 /// maps. The undirected edgeset section's header line is \c \@undiredgeset
1004 /// \c undiredgeset_id, but the \c undiredgeset_id may be empty.
1006 /// The first line of the section contains the names of the maps separated
1007 /// with white spaces. Each next lines describes an edge in the edgeset. The
1008 /// line contains the connected nodes' id and the mapped values for each map.
1010 /// The section can handle the directed as a syntactical sugar. Two
1011 /// undirected edge map describes one directed edge map. This two maps
1012 /// are the forward map and the backward map and the names of this map
1013 /// is near the same just with a prefix \c '+' or \c '-' character
1016 /// If the edgeset contains an \c "id" named map then it will be regarded
1017 /// as id map. This map should contain only unique values and when the
1018 /// \c readId() member will read a value from the given stream it will
1019 /// give back that undiricted edge which is mapped to this value.
1021 /// The undirected edgeset reader needs a node id reader to identify which
1022 /// nodes have to be connected. If a NodeSetReader reads an "id" named map,
1023 /// it will be able to resolve the nodes by ids.
1025 /// \relates LemonReader
1026 template <typename _Graph, typename _Traits = DefaultReaderTraits>
1027 class UndirEdgeSetReader : public CommonSectionReaderBase {
1028 typedef CommonSectionReaderBase Parent;
1031 typedef _Graph Graph;
1032 typedef _Traits Traits;
1033 typedef typename Graph::UndirEdge Item;
1034 typedef typename Traits::Skipper DefaultSkipper;
1036 /// \brief Constructor.
1038 /// Constructor for UndirEdgeSetReader. It creates the UndirEdgeSetReader
1039 /// and attach it into the given LemonReader. The undirected edgeset
1040 /// reader will add the readed undirected edges to the given Graph. It
1041 /// will use the given node id reader to read the source and target
1042 /// nodes of the edges. The reader will read the section only if the
1043 /// \c _id and the \c undiredgset_id are the same.
1044 template <typename NodeIdReader>
1045 UndirEdgeSetReader(LemonReader& _reader,
1046 typename SmartParameter<Graph>::Type _graph,
1047 const NodeIdReader& _nodeIdReader,
1048 const std::string& _id = std::string(),
1049 const DefaultSkipper& _skipper = DefaultSkipper())
1050 : Parent(_reader), graph(_graph), id(_id), skipper(_skipper),
1051 nodeIdReader(new IdReader<typename Graph::Node, NodeIdReader>
1054 /// \brief Destructor.
1056 /// Destructor for UndirEdgeSetReader.
1057 virtual ~UndirEdgeSetReader() {
1058 for (typename MapReaders::iterator it = readers.begin();
1059 it != readers.end(); ++it) {
1065 UndirEdgeSetReader(const UndirEdgeSetReader&);
1066 void operator=(const UndirEdgeSetReader&);
1070 /// \brief Add a new undirected edge map reader command for the reader.
1072 /// Add a new edge undirected map reader command for the reader.
1073 template <typename Map>
1074 UndirEdgeSetReader& readUndirEdgeMap(std::string name, Map& map) {
1076 typename Traits::template Reader<typename Map::Value>, Map,
1077 typename SmartParameter<Map>::Type>(name, map);
1080 template <typename Map>
1081 UndirEdgeSetReader& readUndirEdgeMap(std::string name, const Map& map) {
1083 typename Traits::template Reader<typename Map::Value>, Map,
1084 typename SmartParameter<Map>::Type>(name, map);
1087 /// \brief Add a new undirected edge map reader command for the reader.
1089 /// Add a new edge undirected map reader command for the reader.
1090 template <typename Reader, typename Map>
1091 UndirEdgeSetReader& readUndirEdgeMap(std::string name, Map& map,
1092 const Reader& reader = Reader()) {
1093 return _readMap<Reader, Map, typename SmartParameter<Map>::Type>
1094 (name, map, reader);
1097 template <typename Reader, typename Map>
1098 UndirEdgeSetReader& readUndirEdgeMap(std::string name, const Map& map,
1099 const Reader& reader = Reader()) {
1100 return _readMap<Reader, Map, typename SmartParameter<Map>::Type >
1101 (name, map, reader);
1106 template <typename Reader, typename Map, typename MapParameter>
1107 UndirEdgeSetReader& _readMap(std::string name, MapParameter map,
1108 const Reader& reader = Reader()) {
1109 if (readers.find(name) != readers.end()) {
1111 msg << "Multiple read rule for edge map: " << name;
1112 throw IOParameterError(msg.message());
1115 make_pair(name, new MapReader<Item, Map, Reader>(map, reader)));
1121 /// \brief Add a new undirected edge map skipper command for the reader.
1123 /// Add a new undirected edge map skipper command for the reader.
1124 template <typename Reader>
1125 UndirEdgeSetReader& skipUndirEdgeMap(std::string name,
1126 const Reader& reader = Reader()) {
1127 if (readers.find(name) != readers.end()) {
1129 msg << "Multiple read rule for node map: " << name;
1130 throw IOParameterError(msg.message());
1132 readers.insert(make_pair(name, new SkipReader<Item, Reader>(reader)));
1136 /// \brief Add a new directed edge map reader command for the reader.
1138 /// Add a new directed edge map reader command for the reader.
1139 template <typename Map>
1140 UndirEdgeSetReader& readEdgeMap(std::string name, Map& map) {
1142 typename Traits::template Reader<typename Map::Value>, Map,
1143 typename SmartParameter<Map>::Type>(name, map);
1146 template <typename Map>
1147 UndirEdgeSetReader& readEdgeMap(std::string name, const Map& map) {
1149 typename Traits::template Reader<typename Map::Value>, Map,
1150 typename SmartParameter<Map>::Type>(name, map);
1153 /// \brief Add a new directed edge map reader command for the reader.
1155 /// Add a new directed edge map reader command for the reader.
1156 template <typename Reader, typename Map>
1157 UndirEdgeSetReader& readEdgeMap(std::string name, Map& map,
1158 const Reader& reader = Reader()) {
1159 return _readDirMap<Reader, Map, typename SmartParameter<Map>::Type>
1160 (name, map, reader);
1163 template <typename Reader, typename Map>
1164 UndirEdgeSetReader& readEdgeMap(std::string name, const Map& map,
1165 const Reader& reader = Reader()) {
1166 return _readDirMap<Reader, Map, typename SmartParameter<Map>::Type>
1167 (name, map, reader);
1172 template <typename Reader, typename Map, typename MapParameter>
1173 UndirEdgeSetReader& _readDirMap(std::string name, MapParameter map,
1174 const Reader& reader = Reader()) {
1176 _reader_bits::writeComposeMap(map, forwardMap(graph)), reader);
1178 _reader_bits::writeComposeMap(map, backwardMap(graph)), reader);
1184 /// \brief Add a new directed edge map skipper command for the reader.
1186 /// Add a new directed edge map skipper command for the reader.
1187 template <typename Reader>
1188 UndirEdgeSetReader& skipEdgeMap(std::string name,
1189 const Reader& reader = Reader()) {
1190 skipMap("+" + name, reader);
1191 skipMap("-" + name, reader);
1197 /// \brief Gives back true when the SectionReader can process
1198 /// the section with the given header line.
1200 /// It gives back true when the header line starts with \c \@undiredgeset,
1201 /// and the header line's id and the edgeset's id are the same.
1202 virtual bool header(const std::string& line) {
1203 std::istringstream ls(line);
1204 std::string command;
1206 ls >> command >> name;
1207 return command == "@undiredgeset" && name == id;
1210 /// \brief Reader function of the section.
1212 /// It reads the content of the section.
1213 virtual void read(std::istream& is) {
1214 std::vector<ReaderBase<Item>* > index;
1218 std::istringstream ls(line);
1220 typename MapReaders::iterator it = readers.find(id);
1221 if (it != readers.end()) {
1222 index.push_back(it->second);
1224 index.push_back(&skipper);
1226 if (id == "id" && inverter.get() == 0) {
1227 inverter.reset(index.back()->getInverter());
1228 index.back() = inverter.get();
1231 while (getline(is, line)) {
1232 std::istringstream ls(line);
1233 typename Graph::Node from = nodeIdReader->read(ls);
1234 typename Graph::Node to = nodeIdReader->read(ls);
1235 typename Graph::UndirEdge edge = graph.addEdge(from, to);
1236 for (int i = 0; i < (int)index.size(); ++i) {
1237 index[i]->read(ls, edge);
1244 /// \brief Returns true if the edgeset can give back the edge by its id.
1246 /// Returns true if the edgeset can give back the undirected edge by its
1247 /// id. It is possible only if an "id" named map was read.
1248 bool isIdReader() const {
1249 return inverter.get() != 0;
1252 /// \brief Gives back the undirected edge by its id.
1254 /// It reads an id from the stream and gives back which undirected edge
1255 /// belongs to it. It is possible only if there was read an "id" named map.
1256 Item readId(std::istream& is) const {
1257 return inverter->read(is);
1262 typedef std::map<std::string, ReaderBase<Item>*> MapReaders;
1265 typename SmartReference<Graph>::Type graph;
1267 SkipReader<Item, DefaultSkipper> skipper;
1269 std::auto_ptr<InverterBase<Item> > inverter;
1270 std::auto_ptr<IdReaderBase<typename Graph::Node> > nodeIdReader;
1273 /// \ingroup io_group
1274 /// \brief SectionReader for reading labeled nodes.
1276 /// The nodes section's header line is \c \@nodes \c nodes_id, but the
1277 /// \c nodes_id may be empty.
1279 /// Each line in the section contains the name of the node
1280 /// and then the node id.
1282 /// \relates LemonReader
1283 template <typename _Graph>
1284 class NodeReader : public CommonSectionReaderBase {
1285 typedef CommonSectionReaderBase Parent;
1286 typedef _Graph Graph;
1287 typedef typename Graph::Node Item;
1290 /// \brief Constructor.
1292 /// Constructor for NodeReader. It creates the NodeReader and
1293 /// attach it into the given LemonReader. It will use the given
1294 /// node id reader to give back the nodes. The reader will read the
1295 /// section only if the \c _id and the \c nodes_id are the same.
1296 template <typename _IdReader>
1297 NodeReader(LemonReader& _reader, const _IdReader& _idReader,
1298 const std::string& _id = std::string())
1299 : Parent(_reader), id(_id),
1300 idReader(new IdReader<typename Graph::Node, _IdReader>(_idReader)) {}
1302 /// \brief Destructor.
1304 /// Destructor for NodeReader.
1305 virtual ~NodeReader() {}
1308 NodeReader(const NodeReader&);
1309 void operator=(const NodeReader&);
1313 /// \brief Add a node reader command for the NodeReader.
1315 /// Add a node reader command for the NodeReader.
1316 void readNode(const std::string& name, Item& item) {
1317 if (readers.find(name) != readers.end()) {
1319 msg << "Multiple read rule for node: " << name;
1320 throw IOParameterError(msg.message());
1322 readers.insert(make_pair(name, &item));
1327 /// \brief Gives back true when the SectionReader can process
1328 /// the section with the given header line.
1330 /// It gives back true when the header line start with \c \@nodes,
1331 /// and the header line's id and the reader's id are the same.
1332 virtual bool header(const std::string& line) {
1333 std::istringstream ls(line);
1334 std::string command;
1336 ls >> command >> name;
1337 return command == "@nodes" && name == id;
1340 /// \brief Reader function of the section.
1342 /// It reads the content of the section.
1343 virtual void read(std::istream& is) {
1345 while (getline(is, line)) {
1346 std::istringstream ls(line);
1349 typename ItemReaders::iterator it = readers.find(id);
1350 if (it != readers.end()) {
1351 *(it->second) = idReader->read(ls);
1360 typedef std::map<std::string, Item*> ItemReaders;
1361 ItemReaders readers;
1362 std::auto_ptr<IdReaderBase<Item> > idReader;
1365 /// \ingroup io_group
1366 /// \brief SectionReader for reading labeled edges.
1368 /// The edges section's header line is \c \@edges \c edges_id, but the
1369 /// \c edges_id may be empty.
1371 /// Each line in the section contains the name of the edge
1372 /// and then the edge id.
1374 /// \relates LemonReader
1375 template <typename _Graph>
1376 class EdgeReader : public CommonSectionReaderBase {
1377 typedef CommonSectionReaderBase Parent;
1378 typedef _Graph Graph;
1379 typedef typename Graph::Edge Item;
1382 /// \brief Constructor.
1384 /// Constructor for EdgeReader. It creates the EdgeReader and
1385 /// attach it into the given LemonReader. It will use the given
1386 /// edge id reader to give back the edges. The reader will read the
1387 /// section only if the \c _id and the \c edges_id are the same.
1388 template <typename _IdReader>
1389 EdgeReader(LemonReader& _reader, const _IdReader& _idReader,
1390 const std::string& _id = std::string())
1391 : Parent(_reader), id(_id),
1392 idReader(new IdReader<typename Graph::Edge, _IdReader>(_idReader)) {}
1394 /// \brief Destructor.
1396 /// Destructor for EdgeReader.
1397 virtual ~EdgeReader() {}
1399 EdgeReader(const EdgeReader&);
1400 void operator=(const EdgeReader&);
1404 /// \brief Add an edge reader command for the EdgeReader.
1406 /// Add an edge reader command for the EdgeReader.
1407 void readEdge(const std::string& name, Item& item) {
1408 if (readers.find(name) != readers.end()) {
1410 msg << "Multiple read rule for edge: " << name;
1411 throw IOParameterError(msg.message());
1413 readers.insert(make_pair(name, &item));
1418 /// \brief Gives back true when the SectionReader can process
1419 /// the section with the given header line.
1421 /// It gives back true when the header line start with \c \@edges,
1422 /// and the header line's id and the reader's id are the same.
1423 virtual bool header(const std::string& line) {
1424 std::istringstream ls(line);
1425 std::string command;
1427 ls >> command >> name;
1428 return command == "@edges" && name == id;
1431 /// \brief Reader function of the section.
1433 /// It reads the content of the section.
1434 virtual void read(std::istream& is) {
1436 while (getline(is, line)) {
1437 std::istringstream ls(line);
1440 typename ItemReaders::iterator it = readers.find(id);
1441 if (it != readers.end()) {
1442 *(it->second) = idReader->read(ls);
1451 typedef std::map<std::string, Item*> ItemReaders;
1452 ItemReaders readers;
1453 std::auto_ptr<IdReaderBase<Item> > idReader;
1456 /// \ingroup io_group
1457 /// \brief SectionReader for reading labeled undirected edges.
1459 /// The undirected edges section's header line is \c \@undiredges
1460 /// \c undiredges_id, but the \c undiredges_id may be empty.
1462 /// Each line in the section contains the name of the undirected edge
1463 /// and then the undirected edge id.
1465 /// \relates LemonReader
1466 template <typename _Graph>
1467 class UndirEdgeReader : public CommonSectionReaderBase {
1468 typedef CommonSectionReaderBase Parent;
1469 typedef _Graph Graph;
1470 typedef typename Graph::UndirEdge Item;
1473 /// \brief Constructor.
1475 /// Constructor for UndirEdgeReader. It creates the UndirEdgeReader and
1476 /// attach it into the given LemonReader. It will use the given
1477 /// undirected edge id reader to give back the edges. The reader will
1478 /// read the section only if the \c _id and the \c undiredges_id are
1480 template <typename _IdReader>
1481 UndirEdgeReader(LemonReader& _reader, const _IdReader& _idReader,
1482 const std::string& _id = std::string())
1483 : Parent(_reader), id(_id),
1484 idReader(new IdReader<typename Graph::UndirEdge, _IdReader>(_idReader))
1487 /// \brief Destructor.
1489 /// Destructor for UndirEdgeReader.
1490 virtual ~UndirEdgeReader() {}
1492 UndirEdgeReader(const UndirEdgeReader&);
1493 void operator=(const UndirEdgeReader&);
1497 /// \brief Add an undirected edge reader command for the UndirEdgeReader.
1499 /// Add an undirected edge reader command for the UndirEdgeReader.
1500 void readUndirEdge(const std::string& name, Item& item) {
1501 if (readers.find(name) != readers.end()) {
1503 msg << "Multiple read rule for edge: " << name;
1504 throw IOParameterError(msg.message());
1506 readers.insert(make_pair(name, &item));
1511 /// \brief Gives back true when the SectionReader can process
1512 /// the section with the given header line.
1514 /// It gives back true when the header line start with \c \@edges,
1515 /// and the header line's id and the reader's id are the same.
1516 virtual bool header(const std::string& line) {
1517 std::istringstream ls(line);
1518 std::string command;
1520 ls >> command >> name;
1521 return command == "@edges" && name == id;
1524 /// \brief Reader function of the section.
1526 /// It reads the content of the section.
1527 virtual void read(std::istream& is) {
1529 while (getline(is, line)) {
1530 std::istringstream ls(line);
1533 typename ItemReaders::iterator it = readers.find(id);
1534 if (it != readers.end()) {
1535 *(it->second) = idReader->read(ls);
1544 typedef std::map<std::string, Item*> ItemReaders;
1545 ItemReaders readers;
1546 std::auto_ptr<IdReaderBase<Item> > idReader;
1549 /// \ingroup io_group
1550 /// \brief SectionReader for attributes.
1552 /// The lemon format can store multiple attribute set. Each set has
1553 /// the header line \c \@attributes \c attributeset_id, but the
1554 /// attributeset_id may be empty.
1556 /// The attributeset section contains several lines. Each of them starts
1557 /// with an attribute and then a the value for the id.
1559 /// \relates LemonReader
1560 template <typename _Traits = DefaultReaderTraits>
1561 class AttributeReader : public CommonSectionReaderBase {
1562 typedef CommonSectionReaderBase Parent;
1563 typedef _Traits Traits;
1565 /// \brief Constructor.
1567 /// Constructor for AttributeReader. It creates the AttributeReader and
1568 /// attach it into the given LemonReader. The reader process a section
1569 /// only if the \c section_id and the \c _id are the same.
1570 AttributeReader(LemonReader& _reader,
1571 const std::string& _id = std::string())
1572 : Parent(_reader), id(_id) {}
1574 /// \brief Destructor.
1576 /// Destructor for AttributeReader.
1577 virtual ~AttributeReader() {
1578 for (typename Readers::iterator it = readers.begin();
1579 it != readers.end(); ++it) {
1585 AttributeReader(const AttributeReader&);
1586 void operator=(AttributeReader&);
1589 /// \brief Add an attribute reader command for the reader.
1591 /// Add an attribute reader command for the reader.
1592 template <typename Value>
1593 AttributeReader& readAttribute(const std::string& id, Value& value) {
1594 return readAttribute<typename Traits::template Reader<Value> >
1598 /// \brief Add an attribute reader command for the reader.
1600 /// Add an attribute reader command for the reader.
1601 template <typename Reader, typename Value>
1602 AttributeReader& readAttribute(const std::string& name, Value& value,
1603 const Reader& reader = Reader()) {
1604 if (readers.find(name) != readers.end()) {
1606 msg << "Multiple read rule for attribute: " << name;
1607 throw IOParameterError(msg.message());
1609 readers.insert(make_pair(name, new ValueReader<Value, Reader>
1616 /// \brief Gives back true when the SectionReader can process
1617 /// the section with the given header line.
1619 /// It gives back true when the header line start with \c \@attributes,
1620 /// and the header line's id and the attributeset's id are the same.
1621 bool header(const std::string& line) {
1622 std::istringstream ls(line);
1623 std::string command;
1625 ls >> command >> name;
1626 return command == "@attributes" && name == id;
1629 /// \brief Reader function of the section.
1631 /// It reads the content of the section.
1632 void read(std::istream& is) {
1634 while (getline(is, line)) {
1635 std::istringstream ls(line);
1638 typename Readers::iterator it = readers.find(id);
1639 if (it != readers.end()) {
1640 it->second->read(ls);
1648 typedef std::map<std::string, ValueReaderBase*> Readers;
1652 /// \ingroup io_group
1653 /// \brief SectionReader for retrieve what is in the file.
1655 /// SectionReader for retrieve what is in the file. If you want
1656 /// to know which sections, maps and items are in the file
1657 /// use the next code:
1659 /// LemonReader reader("input.lgf");
1660 /// ContentReader content(reader);
1663 class ContentReader : public LemonReader::SectionReader {
1664 typedef LemonReader::SectionReader Parent;
1666 /// \brief Constructor.
1669 ContentReader(LemonReader& _reader) : Parent(_reader) {}
1671 /// \brief Desctructor.
1674 virtual ~ContentReader() {}
1676 /// \brief Gives back how many nodesets are in the file.
1678 /// Gives back how many nodesets are in the file.
1679 int nodeSetNum() const {
1680 return nodesets.size();
1683 /// \brief Gives back the name of nodeset on the indiced position.
1685 /// Gives back the name of nodeset on the indiced position.
1686 std::string nodeSetName(int index) const {
1687 return nodesets[index].name;
1690 /// \brief Gives back the map names of nodeset on the indiced position.
1692 /// Gives back the map names of nodeset on the indiced position.
1693 const std::vector<std::string>& nodeSetMaps(int index) const {
1694 return nodesets[index].items;
1697 /// \brief Gives back how many edgesets are in the file.
1699 /// Gives back how many edgesets are in the file.
1700 int edgeSetNum() const {
1701 return edgesets.size();
1704 /// \brief Gives back the name of edgeset on the indiced position.
1706 /// Gives back the name of edgeset on the indiced position.
1707 std::string edgeSetName(int index) const {
1708 return edgesets[index].name;
1711 /// \brief Gives back the map names of edgeset on the indiced position.
1713 /// Gives back the map names of edgeset on the indiced position.
1714 const std::vector<std::string>& edgeSetMaps(int index) const {
1715 return edgesets[index].items;
1718 /// \brief Gives back how many undirected edgesets are in the file.
1720 /// Gives back how many undirected edgesets are in the file.
1721 int undirEdgeSetNum() const {
1722 return undiredgesets.size();
1725 /// \brief Gives back the name of undirected edgeset on the indiced
1728 /// Gives back the name of undirected edgeset on the indiced position.
1729 std::string undirEdgeSetName(int index) const {
1730 return undiredgesets[index].name;
1733 /// \brief Gives back the map names of undirected edgeset on the indiced
1736 /// Gives back the map names of undirected edgeset on the indiced position.
1737 const std::vector<std::string>& undirEdgeSetMaps(int index) const {
1738 return undiredgesets[index].items;
1741 /// \brief Gives back how many labeled nodes section are in the file.
1743 /// Gives back how many labeled nodes section are in the file.
1744 int nodesNum() const {
1745 return nodes.size();
1748 /// \brief Gives back the name of labeled nodes section on the indiced
1751 /// Gives back the name of labeled nodes section on the indiced position.
1752 std::string nodesName(int index) const {
1753 return nodes[index].name;
1756 /// \brief Gives back the names of the labeled nodes in the indiced
1759 /// Gives back the names of the labeled nodes in the indiced section.
1760 const std::vector<std::string>& nodesItems(int index) const {
1761 return nodes[index].items;
1764 /// \brief Gives back how many labeled edges section are in the file.
1766 /// Gives back how many labeled edges section are in the file.
1767 int edgesNum() const {
1768 return edges.size();
1771 /// \brief Gives back the name of labeled edges section on the indiced
1774 /// Gives back the name of labeled edges section on the indiced position.
1775 std::string edgesName(int index) const {
1776 return edges[index].name;
1779 /// \brief Gives back the names of the labeled edges in the indiced
1782 /// Gives back the names of the labeled edges in the indiced section.
1783 const std::vector<std::string>& edgesItems(int index) const {
1784 return edges[index].items;
1787 /// \brief Gives back how many labeled undirected edges section are
1790 /// Gives back how many labeled undirected edges section are in the file.
1791 int undirEdgesNum() const {
1792 return undiredges.size();
1795 /// \brief Gives back the name of labeled undirected edges section
1796 /// on the indiced position.
1798 /// Gives back the name of labeled undirected edges section on the
1799 /// indiced position.
1800 std::string undirEdgesName(int index) const {
1801 return undiredges[index].name;
1804 /// \brief Gives back the names of the labeled undirected edges in
1805 /// the indiced section.
1807 /// Gives back the names of the labeled undirected edges in the
1808 /// indiced section.
1809 const std::vector<std::string>& undirEdgesItems(int index) const {
1810 return undiredges[index].items;
1814 /// \brief Gives back how many attributes section are in the file.
1816 /// Gives back how many attributes section are in the file.
1817 int attributesNum() const {
1818 return attributes.size();
1821 /// \brief Gives back the name of attributes section on the indiced
1824 /// Gives back the name of attributes section on the indiced position.
1825 std::string attributesName(int index) const {
1826 return attributes[index].name;
1829 /// \brief Gives back the names of the attributes in the indiced section.
1831 /// Gives back the names of the attributes in the indiced section.
1832 const std::vector<std::string>& attributesItems(int index) const {
1833 return attributes[index].items;
1836 const std::vector<std::string>& otherSections() const {
1842 /// \brief Gives back true when the SectionReader can process
1843 /// the section with the given header line.
1845 /// It gives back true when the section is common section.
1846 bool header(const std::string& line) {
1847 std::istringstream ls(line);
1848 std::string command, name;
1849 ls >> command >> name;
1850 if (command == "@nodeset") {
1852 nodesets.push_back(SectionInfo(name));
1853 } else if (command == "@edgeset") {
1855 edgesets.push_back(SectionInfo(name));
1856 } else if (command == "@undiredgeset") {
1858 undiredgesets.push_back(SectionInfo(name));
1859 } else if (command == "@nodes") {
1861 nodes.push_back(SectionInfo(name));
1862 } else if (command == "@edges") {
1864 edges.push_back(SectionInfo(name));
1865 } else if (command == "@undiredges") {
1867 undiredges.push_back(SectionInfo(name));
1868 } else if (command == "@attributes") {
1870 attributes.push_back(SectionInfo(name));
1872 sections.push_back(line);
1878 /// \brief Retrieve the items from various sections.
1880 /// Retrieve the items from various sections.
1881 void read(std::istream& is) {
1882 if (current == "@nodeset") {
1883 readMapNames(is, nodesets.back().items);
1884 } else if (current == "@edgeset") {
1885 readMapNames(is, edgesets.back().items);
1886 } else if (current == "@undiredgeset") {
1887 readMapNames(is, undiredgesets.back().items);
1888 } else if (current == "@nodes") {
1889 readItemNames(is, nodes.back().items);
1890 } else if (current == "@edges") {
1891 readItemNames(is, edges.back().items);
1892 } else if (current == "@undiredges") {
1893 readItemNames(is, undiredges.back().items);
1894 } else if (current == "@attributes") {
1895 readItemNames(is, attributes.back().items);
1901 void readMapNames(std::istream& is, std::vector<std::string>& maps) {
1902 std::string line, id;
1903 std::getline(is, line);
1904 std::istringstream ls(line);
1908 while (getline(is, line));
1911 void readItemNames(std::istream& is, std::vector<std::string>& maps) {
1912 std::string line, id;
1913 while (std::getline(is, line)) {
1914 std::istringstream ls(line);
1920 struct SectionInfo {
1922 std::vector<std::string> items;
1924 SectionInfo(const std::string& _name) : name(_name) {}
1927 std::vector<SectionInfo> nodesets;
1928 std::vector<SectionInfo> edgesets;
1929 std::vector<SectionInfo> undiredgesets;
1931 std::vector<SectionInfo> nodes;
1932 std::vector<SectionInfo> edges;
1933 std::vector<SectionInfo> undiredges;
1935 std::vector<SectionInfo> attributes;
1937 std::vector<std::string> sections;
1939 std::string current;