alpar@209: /* -*- mode: C++; indent-tabs-mode: nil; -*- deba@127: * alpar@209: * This file is a part of LEMON, a generic C++ optimization library. deba@127: * alpar@949: * Copyright (C) 2003-2011 deba@127: * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport deba@127: * (Egervary Research Group on Combinatorial Optimization, EGRES). deba@127: * deba@127: * Permission to use, modify and distribute this software is granted deba@127: * provided that this copyright notice appears in all copies. For deba@127: * precise terms see the accompanying LICENSE file. deba@127: * deba@127: * This software is provided "AS IS" with no warranty of any kind, deba@127: * express or implied, and with no claim as to its suitability for any deba@127: * purpose. deba@127: * deba@127: */ deba@127: deba@127: ///\ingroup lemon_io deba@127: ///\file ladanyi@236: ///\brief \ref lgf-format "LEMON Graph Format" reader. deba@127: deba@127: deba@127: #ifndef LEMON_LGF_READER_H deba@127: #define LEMON_LGF_READER_H deba@127: deba@127: #include deba@127: #include deba@127: #include deba@127: deba@127: #include deba@127: #include deba@127: deba@220: #include deba@127: deba@127: #include deba@127: deba@127: #include deba@127: #include deba@127: deba@127: namespace lemon { deba@127: deba@127: namespace _reader_bits { deba@127: deba@127: template deba@127: struct DefaultConverter { deba@127: Value operator()(const std::string& str) { alpar@209: std::istringstream is(str); alpar@209: Value value; deba@290: if (!(is >> value)) { deba@290: throw FormatError("Cannot read token"); deba@290: } alpar@209: alpar@209: char c; alpar@209: if (is >> std::ws >> c) { deba@290: throw FormatError("Remaining characters in token"); alpar@209: } alpar@209: return value; deba@127: } deba@127: }; deba@127: deba@127: template <> deba@127: struct DefaultConverter { deba@127: std::string operator()(const std::string& str) { alpar@209: return str; deba@127: } deba@127: }; deba@127: alpar@209: template deba@127: class MapStorageBase { deba@127: public: deba@127: typedef _Item Item; deba@127: deba@127: public: deba@127: MapStorageBase() {} deba@127: virtual ~MapStorageBase() {} deba@127: deba@127: virtual void set(const Item& item, const std::string& value) = 0; deba@127: deba@127: }; deba@127: alpar@209: template > deba@127: class MapStorage : public MapStorageBase<_Item> { deba@127: public: deba@127: typedef _Map Map; deba@127: typedef _Converter Converter; deba@127: typedef _Item Item; alpar@209: deba@127: private: deba@127: Map& _map; deba@127: Converter _converter; deba@127: deba@127: public: alpar@209: MapStorage(Map& map, const Converter& converter = Converter()) alpar@209: : _map(map), _converter(converter) {} deba@127: virtual ~MapStorage() {} deba@127: deba@127: virtual void set(const Item& item ,const std::string& value) { alpar@209: _map.set(item, _converter(value)); deba@127: } deba@127: }; deba@127: deba@598: template > deba@598: class GraphArcMapStorage : public MapStorageBase { deba@165: public: deba@165: typedef _Map Map; deba@165: typedef _Converter Converter; deba@598: typedef _GR GR; deba@598: typedef typename GR::Edge Item; deba@165: static const bool dir = _dir; alpar@209: deba@165: private: deba@598: const GR& _graph; deba@165: Map& _map; deba@165: Converter _converter; deba@165: deba@165: public: deba@598: GraphArcMapStorage(const GR& graph, Map& map, alpar@209: const Converter& converter = Converter()) alpar@209: : _graph(graph), _map(map), _converter(converter) {} deba@165: virtual ~GraphArcMapStorage() {} deba@165: deba@165: virtual void set(const Item& item ,const std::string& value) { alpar@209: _map.set(_graph.direct(item, dir), _converter(value)); deba@165: } deba@165: }; deba@165: deba@127: class ValueStorageBase { deba@127: public: deba@127: ValueStorageBase() {} deba@127: virtual ~ValueStorageBase() {} deba@127: deba@127: virtual void set(const std::string&) = 0; deba@127: }; deba@127: deba@127: template > deba@127: class ValueStorage : public ValueStorageBase { deba@127: public: deba@127: typedef _Value Value; deba@127: typedef _Converter Converter; deba@127: deba@127: private: deba@127: Value& _value; deba@127: Converter _converter; deba@127: deba@127: public: deba@127: ValueStorage(Value& value, const Converter& converter = Converter()) kpeter@212: : _value(value), _converter(converter) {} deba@127: deba@127: virtual void set(const std::string& value) { alpar@209: _value = _converter(value); deba@127: } deba@127: }; deba@127: deba@127: template deba@127: struct MapLookUpConverter { deba@127: const std::map& _map; deba@127: deba@127: MapLookUpConverter(const std::map& map) deba@127: : _map(map) {} deba@127: deba@127: Value operator()(const std::string& str) { deba@127: typename std::map::const_iterator it = deba@127: _map.find(str); deba@127: if (it == _map.end()) { deba@127: std::ostringstream msg; deba@127: msg << "Item not found: " << str; deba@290: throw FormatError(msg.str()); deba@127: } deba@127: return it->second; deba@127: } deba@127: }; deba@127: deba@598: template deba@165: struct GraphArcLookUpConverter { deba@598: const GR& _graph; deba@598: const std::map& _map; deba@598: deba@598: GraphArcLookUpConverter(const GR& graph, alpar@209: const std::map& map) alpar@209: : _graph(graph), _map(map) {} alpar@209: deba@598: typename GR::Arc operator()(const std::string& str) { alpar@209: if (str.empty() || (str[0] != '+' && str[0] != '-')) { deba@290: throw FormatError("Item must start with '+' or '-'"); alpar@209: } deba@598: typename std::map alpar@209: ::const_iterator it = _map.find(str.substr(1)); alpar@209: if (it == _map.end()) { deba@290: throw FormatError("Item not found"); alpar@209: } alpar@209: return _graph.direct(it->second, str[0] == '+'); deba@165: } deba@165: }; deba@165: deba@197: inline bool isWhiteSpace(char c) { alpar@209: return c == ' ' || c == '\t' || c == '\v' || alpar@209: c == '\n' || c == '\r' || c == '\f'; deba@127: } alpar@209: deba@197: inline bool isOct(char c) { alpar@209: return '0' <= c && c <='7'; deba@127: } alpar@209: deba@197: inline int valueOct(char c) { deba@127: LEMON_ASSERT(isOct(c), "The character is not octal."); deba@127: return c - '0'; deba@127: } deba@127: deba@197: inline bool isHex(char c) { alpar@209: return ('0' <= c && c <= '9') || alpar@209: ('a' <= c && c <= 'z') || alpar@209: ('A' <= c && c <= 'Z'); deba@127: } alpar@209: deba@197: inline int valueHex(char c) { deba@127: LEMON_ASSERT(isHex(c), "The character is not hexadecimal."); deba@127: if ('0' <= c && c <= '9') return c - '0'; deba@127: if ('a' <= c && c <= 'z') return c - 'a' + 10; deba@127: return c - 'A' + 10; deba@127: } deba@127: deba@197: inline bool isIdentifierFirstChar(char c) { deba@127: return ('a' <= c && c <= 'z') || alpar@209: ('A' <= c && c <= 'Z') || c == '_'; deba@127: } deba@127: deba@197: inline bool isIdentifierChar(char c) { deba@127: return isIdentifierFirstChar(c) || alpar@209: ('0' <= c && c <= '9'); deba@127: } deba@127: deba@197: inline char readEscape(std::istream& is) { deba@127: char c; deba@127: if (!is.get(c)) deba@290: throw FormatError("Escape format error"); deba@127: deba@127: switch (c) { deba@127: case '\\': alpar@209: return '\\'; deba@127: case '\"': alpar@209: return '\"'; deba@127: case '\'': alpar@209: return '\''; deba@127: case '\?': alpar@209: return '\?'; deba@127: case 'a': alpar@209: return '\a'; deba@127: case 'b': alpar@209: return '\b'; deba@127: case 'f': alpar@209: return '\f'; deba@127: case 'n': alpar@209: return '\n'; deba@127: case 'r': alpar@209: return '\r'; deba@127: case 't': alpar@209: return '\t'; deba@127: case 'v': alpar@209: return '\v'; deba@127: case 'x': alpar@209: { alpar@209: int code; alpar@209: if (!is.get(c) || !isHex(c)) deba@290: throw FormatError("Escape format error"); alpar@209: else if (code = valueHex(c), !is.get(c) || !isHex(c)) is.putback(c); alpar@209: else code = code * 16 + valueHex(c); alpar@209: return code; alpar@209: } deba@127: default: alpar@209: { alpar@209: int code; alpar@209: if (!isOct(c)) deba@290: throw FormatError("Escape format error"); alpar@209: else if (code = valueOct(c), !is.get(c) || !isOct(c)) alpar@209: is.putback(c); alpar@209: else if (code = code * 8 + valueOct(c), !is.get(c) || !isOct(c)) alpar@209: is.putback(c); alpar@209: else code = code * 8 + valueOct(c); alpar@209: return code; alpar@209: } alpar@209: } deba@127: } alpar@209: deba@197: inline std::istream& readToken(std::istream& is, std::string& str) { deba@127: std::ostringstream os; deba@127: deba@127: char c; deba@127: is >> std::ws; alpar@209: alpar@209: if (!is.get(c)) alpar@209: return is; deba@127: deba@127: if (c == '\"') { alpar@209: while (is.get(c) && c != '\"') { alpar@209: if (c == '\\') alpar@209: c = readEscape(is); alpar@209: os << c; alpar@209: } alpar@209: if (!is) deba@290: throw FormatError("Quoted format error"); deba@127: } else { alpar@209: is.putback(c); alpar@209: while (is.get(c) && !isWhiteSpace(c)) { alpar@209: if (c == '\\') alpar@209: c = readEscape(is); alpar@209: os << c; alpar@209: } alpar@209: if (!is) { alpar@209: is.clear(); alpar@209: } else { alpar@209: is.putback(c); alpar@209: } deba@127: } deba@127: str = os.str(); deba@127: return is; deba@127: } deba@162: deba@162: class Section { deba@162: public: deba@162: virtual ~Section() {} deba@162: virtual void process(std::istream& is, int& line_num) = 0; deba@162: }; deba@162: deba@162: template deba@162: class LineSection : public Section { deba@162: private: deba@162: deba@162: Functor _functor; deba@162: deba@162: public: alpar@209: deba@162: LineSection(const Functor& functor) : _functor(functor) {} deba@162: virtual ~LineSection() {} deba@162: deba@162: virtual void process(std::istream& is, int& line_num) { alpar@209: char c; alpar@209: std::string line; alpar@209: while (is.get(c) && c != '@') { alpar@209: if (c == '\n') { alpar@209: ++line_num; alpar@209: } else if (c == '#') { alpar@209: getline(is, line); alpar@209: ++line_num; alpar@209: } else if (!isWhiteSpace(c)) { alpar@209: is.putback(c); alpar@209: getline(is, line); alpar@209: _functor(line); alpar@209: ++line_num; alpar@209: } alpar@209: } alpar@209: if (is) is.putback(c); alpar@209: else if (is.eof()) is.clear(); deba@162: } deba@162: }; deba@162: deba@162: template deba@162: class StreamSection : public Section { deba@162: private: deba@162: deba@162: Functor _functor; deba@162: deba@162: public: alpar@209: deba@162: StreamSection(const Functor& functor) : _functor(functor) {} alpar@209: virtual ~StreamSection() {} deba@162: deba@162: virtual void process(std::istream& is, int& line_num) { alpar@209: _functor(is, line_num); alpar@209: char c; alpar@209: std::string line; alpar@209: while (is.get(c) && c != '@') { alpar@209: if (c == '\n') { alpar@209: ++line_num; alpar@209: } else if (!isWhiteSpace(c)) { alpar@209: getline(is, line); alpar@209: ++line_num; alpar@209: } alpar@209: } alpar@209: if (is) is.putback(c); alpar@209: else if (is.eof()) is.clear(); deba@162: } deba@162: }; alpar@209: deba@127: } alpar@156: deba@598: template deba@190: class DigraphReader; deba@190: deba@598: template deba@598: DigraphReader digraphReader(TDGR& digraph, std::istream& is = std::cin); deba@598: template deba@598: DigraphReader digraphReader(TDGR& digraph, const std::string& fn); deba@598: template deba@598: DigraphReader digraphReader(TDGR& digraph, const char *fn); deba@190: alpar@156: /// \ingroup lemon_io alpar@209: /// kpeter@192: /// \brief \ref lgf-format "LGF" reader for directed graphs alpar@156: /// alpar@156: /// This utility reads an \ref lgf-format "LGF" file. alpar@156: /// alpar@156: /// The reading method does a batch processing. The user creates a alpar@156: /// reader object, then various reading rules can be added to the alpar@156: /// reader, and eventually the reading is executed with the \c run() alpar@156: /// member function. A map reading rule can be added to the reader alpar@156: /// with the \c nodeMap() or \c arcMap() members. An optional deba@162: /// converter parameter can also be added as a standard functor kpeter@192: /// converting from \c std::string to the value type of the map. If it deba@162: /// is set, it will determine how the tokens in the file should be kpeter@192: /// converted to the value type of the map. If the functor is not set, deba@162: /// then a default conversion will be used. One map can be read into deba@162: /// multiple map objects at the same time. The \c attribute(), \c deba@162: /// node() and \c arc() functions are used to add attribute reading deba@162: /// rules. alpar@156: /// alpar@156: ///\code deba@598: /// DigraphReader(digraph, std::cin). kpeter@192: /// nodeMap("coordinates", coord_map). kpeter@192: /// arcMap("capacity", cap_map). kpeter@192: /// node("source", src). kpeter@192: /// node("target", trg). kpeter@192: /// attribute("caption", caption). kpeter@192: /// run(); alpar@156: ///\endcode alpar@156: /// alpar@156: /// By default the reader uses the first section in the file of the alpar@156: /// proper type. If a section has an optional name, then it can be deba@162: /// selected for reading by giving an optional name parameter to the deba@189: /// \c nodes(), \c arcs() or \c attributes() functions. alpar@156: /// alpar@156: /// The \c useNodes() and \c useArcs() functions are used to tell the reader alpar@156: /// that the nodes or arcs should not be constructed (added to the alpar@156: /// graph) during the reading, but instead the label map of the items alpar@156: /// are given as a parameter of these functions. An kpeter@192: /// application of these functions is multipass reading, which is kpeter@192: /// important if two \c \@arcs sections must be read from the kpeter@192: /// file. In this case the first phase would read the node set and one alpar@156: /// of the arc sets, while the second phase would read the second arc alpar@156: /// set into an \e ArcSet class (\c SmartArcSet or \c ListArcSet). alpar@156: /// The previously read label node map should be passed to the \c alpar@156: /// useNodes() functions. Another application of multipass reading when alpar@210: /// paths are given as a node map or an arc map. alpar@210: /// It is impossible to read this in alpar@156: /// a single pass, because the arcs are not constructed when the node alpar@156: /// maps are read. deba@598: template deba@127: class DigraphReader { deba@127: public: deba@127: deba@598: typedef DGR Digraph; alpar@209: deba@127: private: deba@127: deba@598: TEMPLATE_DIGRAPH_TYPEDEFS(DGR); deba@127: deba@127: std::istream* _is; deba@127: bool local_is; deba@290: std::string _filename; deba@127: deba@598: DGR& _digraph; deba@127: deba@127: std::string _nodes_caption; deba@127: std::string _arcs_caption; deba@127: std::string _attributes_caption; deba@127: deba@127: typedef std::map NodeIndex; deba@127: NodeIndex _node_index; deba@127: typedef std::map ArcIndex; deba@127: ArcIndex _arc_index; alpar@209: alpar@209: typedef std::vector*> > NodeMaps; alpar@209: NodeMaps _node_maps; deba@127: deba@127: typedef std::vector*> >ArcMaps; deba@127: ArcMaps _arc_maps; deba@127: alpar@209: typedef std::multimap deba@127: Attributes; deba@127: Attributes _attributes; deba@127: deba@127: bool _use_nodes; deba@127: bool _use_arcs; deba@127: deba@188: bool _skip_nodes; deba@188: bool _skip_arcs; deba@188: deba@127: int line_num; deba@127: std::istringstream line; deba@127: deba@127: public: deba@127: alpar@156: /// \brief Constructor alpar@156: /// alpar@156: /// Construct a directed graph reader, which reads from the given alpar@156: /// input stream. deba@598: DigraphReader(DGR& digraph, std::istream& is = std::cin) deba@127: : _is(&is), local_is(false), _digraph(digraph), alpar@209: _use_nodes(false), _use_arcs(false), alpar@209: _skip_nodes(false), _skip_arcs(false) {} deba@127: alpar@156: /// \brief Constructor alpar@156: /// alpar@156: /// Construct a directed graph reader, which reads from the given alpar@156: /// file. deba@598: DigraphReader(DGR& digraph, const std::string& fn) deba@290: : _is(new std::ifstream(fn.c_str())), local_is(true), deba@290: _filename(fn), _digraph(digraph), kpeter@212: _use_nodes(false), _use_arcs(false), deba@290: _skip_nodes(false), _skip_arcs(false) { deba@295: if (!(*_is)) { deba@295: delete _is; deba@295: throw IoError("Cannot open file", fn); deba@295: } deba@290: } alpar@209: alpar@156: /// \brief Constructor alpar@156: /// alpar@156: /// Construct a directed graph reader, which reads from the given alpar@156: /// file. deba@598: DigraphReader(DGR& digraph, const char* fn) deba@290: : _is(new std::ifstream(fn)), local_is(true), deba@290: _filename(fn), _digraph(digraph), kpeter@212: _use_nodes(false), _use_arcs(false), deba@290: _skip_nodes(false), _skip_arcs(false) { deba@295: if (!(*_is)) { deba@295: delete _is; deba@295: throw IoError("Cannot open file", fn); deba@295: } deba@290: } deba@127: alpar@156: /// \brief Destructor deba@127: ~DigraphReader() { alpar@209: for (typename NodeMaps::iterator it = _node_maps.begin(); alpar@209: it != _node_maps.end(); ++it) { alpar@209: delete it->second; deba@127: } deba@127: alpar@209: for (typename ArcMaps::iterator it = _arc_maps.begin(); alpar@209: it != _arc_maps.end(); ++it) { alpar@209: delete it->second; deba@127: } deba@127: alpar@209: for (typename Attributes::iterator it = _attributes.begin(); alpar@209: it != _attributes.end(); ++it) { alpar@209: delete it->second; deba@127: } deba@127: deba@127: if (local_is) { alpar@209: delete _is; deba@127: } deba@127: deba@127: } deba@127: deba@127: private: deba@190: deba@598: template deba@598: friend DigraphReader digraphReader(TDGR& digraph, std::istream& is); deba@598: template deba@598: friend DigraphReader digraphReader(TDGR& digraph, deba@598: const std::string& fn); deba@598: template deba@598: friend DigraphReader digraphReader(TDGR& digraph, const char *fn); alpar@209: alpar@209: DigraphReader(DigraphReader& other) deba@190: : _is(other._is), local_is(other.local_is), _digraph(other._digraph), alpar@209: _use_nodes(other._use_nodes), _use_arcs(other._use_arcs), alpar@209: _skip_nodes(other._skip_nodes), _skip_arcs(other._skip_arcs) { deba@190: deba@190: other._is = 0; deba@190: other.local_is = false; alpar@209: deba@190: _node_index.swap(other._node_index); deba@190: _arc_index.swap(other._arc_index); deba@190: deba@190: _node_maps.swap(other._node_maps); deba@190: _arc_maps.swap(other._arc_maps); deba@190: _attributes.swap(other._attributes); deba@190: deba@190: _nodes_caption = other._nodes_caption; deba@190: _arcs_caption = other._arcs_caption; deba@190: _attributes_caption = other._attributes_caption; deba@190: deba@190: } deba@190: deba@127: DigraphReader& operator=(const DigraphReader&); deba@127: deba@127: public: deba@127: kpeter@584: /// \name Reading Rules alpar@156: /// @{ alpar@209: alpar@156: /// \brief Node map reading rule alpar@156: /// alpar@156: /// Add a node map reading rule to the reader. deba@127: template deba@127: DigraphReader& nodeMap(const std::string& caption, Map& map) { deba@127: checkConcept, Map>(); alpar@209: _reader_bits::MapStorageBase* storage = alpar@209: new _reader_bits::MapStorage(map); deba@127: _node_maps.push_back(std::make_pair(caption, storage)); deba@127: return *this; deba@127: } deba@127: alpar@156: /// \brief Node map reading rule alpar@156: /// alpar@156: /// Add a node map reading rule with specialized converter to the alpar@156: /// reader. deba@127: template alpar@209: DigraphReader& nodeMap(const std::string& caption, Map& map, alpar@209: const Converter& converter = Converter()) { deba@127: checkConcept, Map>(); alpar@209: _reader_bits::MapStorageBase* storage = alpar@209: new _reader_bits::MapStorage(map, converter); deba@127: _node_maps.push_back(std::make_pair(caption, storage)); deba@127: return *this; deba@127: } deba@127: alpar@156: /// \brief Arc map reading rule alpar@156: /// alpar@156: /// Add an arc map reading rule to the reader. deba@127: template deba@127: DigraphReader& arcMap(const std::string& caption, Map& map) { deba@127: checkConcept, Map>(); alpar@209: _reader_bits::MapStorageBase* storage = alpar@209: new _reader_bits::MapStorage(map); deba@127: _arc_maps.push_back(std::make_pair(caption, storage)); deba@127: return *this; deba@127: } deba@127: alpar@156: /// \brief Arc map reading rule alpar@156: /// alpar@156: /// Add an arc map reading rule with specialized converter to the alpar@156: /// reader. deba@127: template alpar@209: DigraphReader& arcMap(const std::string& caption, Map& map, alpar@209: const Converter& converter = Converter()) { deba@127: checkConcept, Map>(); alpar@209: _reader_bits::MapStorageBase* storage = alpar@209: new _reader_bits::MapStorage(map, converter); deba@127: _arc_maps.push_back(std::make_pair(caption, storage)); deba@127: return *this; deba@127: } deba@127: alpar@156: /// \brief Attribute reading rule alpar@156: /// alpar@156: /// Add an attribute reading rule to the reader. deba@127: template deba@127: DigraphReader& attribute(const std::string& caption, Value& value) { alpar@209: _reader_bits::ValueStorageBase* storage = alpar@209: new _reader_bits::ValueStorage(value); deba@127: _attributes.insert(std::make_pair(caption, storage)); deba@127: return *this; deba@127: } deba@127: alpar@156: /// \brief Attribute reading rule alpar@156: /// alpar@156: /// Add an attribute reading rule with specialized converter to the alpar@156: /// reader. deba@127: template alpar@209: DigraphReader& attribute(const std::string& caption, Value& value, alpar@209: const Converter& converter = Converter()) { alpar@209: _reader_bits::ValueStorageBase* storage = alpar@209: new _reader_bits::ValueStorage(value, converter); deba@127: _attributes.insert(std::make_pair(caption, storage)); deba@127: return *this; deba@127: } deba@127: alpar@156: /// \brief Node reading rule alpar@156: /// alpar@156: /// Add a node reading rule to reader. deba@127: DigraphReader& node(const std::string& caption, Node& node) { deba@127: typedef _reader_bits::MapLookUpConverter Converter; deba@127: Converter converter(_node_index); alpar@209: _reader_bits::ValueStorageBase* storage = alpar@209: new _reader_bits::ValueStorage(node, converter); deba@127: _attributes.insert(std::make_pair(caption, storage)); deba@127: return *this; deba@127: } deba@127: alpar@156: /// \brief Arc reading rule alpar@156: /// alpar@156: /// Add an arc reading rule to reader. deba@127: DigraphReader& arc(const std::string& caption, Arc& arc) { deba@127: typedef _reader_bits::MapLookUpConverter Converter; deba@127: Converter converter(_arc_index); alpar@209: _reader_bits::ValueStorageBase* storage = alpar@209: new _reader_bits::ValueStorage(arc, converter); deba@127: _attributes.insert(std::make_pair(caption, storage)); deba@127: return *this; deba@127: } deba@127: alpar@156: /// @} alpar@156: kpeter@584: /// \name Select Section by Name alpar@156: /// @{ alpar@156: alpar@156: /// \brief Set \c \@nodes section to be read alpar@156: /// alpar@156: /// Set \c \@nodes section to be read deba@127: DigraphReader& nodes(const std::string& caption) { deba@127: _nodes_caption = caption; deba@127: return *this; deba@127: } deba@127: alpar@156: /// \brief Set \c \@arcs section to be read alpar@156: /// alpar@156: /// Set \c \@arcs section to be read deba@127: DigraphReader& arcs(const std::string& caption) { deba@127: _arcs_caption = caption; deba@127: return *this; deba@127: } deba@127: alpar@156: /// \brief Set \c \@attributes section to be read alpar@156: /// alpar@156: /// Set \c \@attributes section to be read deba@127: DigraphReader& attributes(const std::string& caption) { deba@127: _attributes_caption = caption; deba@127: return *this; deba@127: } deba@127: alpar@156: /// @} alpar@156: kpeter@584: /// \name Using Previously Constructed Node or Arc Set alpar@156: /// @{ alpar@156: alpar@156: /// \brief Use previously constructed node set alpar@156: /// alpar@156: /// Use previously constructed node set, and specify the node alpar@156: /// label map. deba@127: template deba@127: DigraphReader& useNodes(const Map& map) { deba@127: checkConcept, Map>(); alpar@209: LEMON_ASSERT(!_use_nodes, "Multiple usage of useNodes() member"); deba@127: _use_nodes = true; deba@127: _writer_bits::DefaultConverter converter; deba@127: for (NodeIt n(_digraph); n != INVALID; ++n) { alpar@209: _node_index.insert(std::make_pair(converter(map[n]), n)); deba@127: } deba@127: return *this; deba@127: } deba@127: alpar@156: /// \brief Use previously constructed node set alpar@156: /// alpar@156: /// Use previously constructed node set, and specify the node alpar@156: /// label map and a functor which converts the label map values to kpeter@192: /// \c std::string. deba@127: template alpar@209: DigraphReader& useNodes(const Map& map, alpar@209: const Converter& converter = Converter()) { deba@127: checkConcept, Map>(); alpar@209: LEMON_ASSERT(!_use_nodes, "Multiple usage of useNodes() member"); deba@127: _use_nodes = true; deba@127: for (NodeIt n(_digraph); n != INVALID; ++n) { alpar@209: _node_index.insert(std::make_pair(converter(map[n]), n)); deba@127: } deba@127: return *this; deba@127: } deba@127: alpar@156: /// \brief Use previously constructed arc set alpar@156: /// alpar@156: /// Use previously constructed arc set, and specify the arc alpar@156: /// label map. deba@127: template deba@127: DigraphReader& useArcs(const Map& map) { deba@127: checkConcept, Map>(); deba@127: LEMON_ASSERT(!_use_arcs, "Multiple usage of useArcs() member"); deba@127: _use_arcs = true; deba@127: _writer_bits::DefaultConverter converter; deba@127: for (ArcIt a(_digraph); a != INVALID; ++a) { alpar@209: _arc_index.insert(std::make_pair(converter(map[a]), a)); deba@127: } deba@127: return *this; deba@127: } deba@127: alpar@156: /// \brief Use previously constructed arc set alpar@156: /// alpar@156: /// Use previously constructed arc set, and specify the arc alpar@156: /// label map and a functor which converts the label map values to kpeter@192: /// \c std::string. deba@127: template alpar@209: DigraphReader& useArcs(const Map& map, alpar@209: const Converter& converter = Converter()) { deba@127: checkConcept, Map>(); alpar@209: LEMON_ASSERT(!_use_arcs, "Multiple usage of useArcs() member"); deba@127: _use_arcs = true; deba@127: for (ArcIt a(_digraph); a != INVALID; ++a) { alpar@209: _arc_index.insert(std::make_pair(converter(map[a]), a)); deba@127: } deba@127: return *this; deba@127: } deba@127: deba@188: /// \brief Skips the reading of node section deba@188: /// deba@188: /// Omit the reading of the node section. This implies that each node kpeter@192: /// map reading rule will be abandoned, and the nodes of the graph deba@188: /// will not be constructed, which usually cause that the arc set kpeter@192: /// could not be read due to lack of node name resolving. kpeter@192: /// Therefore \c skipArcs() function should also be used, or kpeter@192: /// \c useNodes() should be used to specify the label of the nodes. deba@188: DigraphReader& skipNodes() { alpar@209: LEMON_ASSERT(!_skip_nodes, "Skip nodes already set"); deba@188: _skip_nodes = true; deba@188: return *this; deba@188: } deba@188: deba@188: /// \brief Skips the reading of arc section deba@188: /// deba@188: /// Omit the reading of the arc section. This implies that each arc kpeter@192: /// map reading rule will be abandoned, and the arcs of the graph deba@188: /// will not be constructed. deba@188: DigraphReader& skipArcs() { alpar@209: LEMON_ASSERT(!_skip_arcs, "Skip arcs already set"); deba@188: _skip_arcs = true; deba@188: return *this; deba@188: } deba@188: alpar@156: /// @} alpar@156: deba@127: private: deba@127: deba@127: bool readLine() { deba@127: std::string str; deba@127: while(++line_num, std::getline(*_is, str)) { alpar@209: line.clear(); line.str(str); alpar@209: char c; alpar@209: if (line >> std::ws >> c && c != '#') { alpar@209: line.putback(c); alpar@209: return true; alpar@209: } deba@127: } deba@127: return false; deba@127: } deba@127: deba@127: bool readSuccess() { deba@127: return static_cast(*_is); deba@127: } alpar@209: deba@127: void skipSection() { deba@127: char c; deba@127: while (readSuccess() && line >> c && c != '@') { alpar@209: readLine(); deba@127: } deba@427: if (readSuccess()) { deba@427: line.putback(c); deba@427: } deba@127: } deba@127: deba@127: void readNodes() { deba@127: deba@127: std::vector map_index(_node_maps.size()); deba@127: int map_num, label_index; deba@127: deba@186: char c; deba@186: if (!readLine() || !(line >> c) || c == '@') { alpar@209: if (readSuccess() && line) line.putback(c); alpar@209: if (!_node_maps.empty()) deba@290: throw FormatError("Cannot find map names"); alpar@209: return; deba@186: } deba@186: line.putback(c); deba@186: deba@127: { alpar@209: std::map maps; alpar@209: alpar@209: std::string map; alpar@209: int index = 0; alpar@209: while (_reader_bits::readToken(line, map)) { alpar@209: if (maps.find(map) != maps.end()) { alpar@209: std::ostringstream msg; alpar@209: msg << "Multiple occurence of node map: " << map; deba@290: throw FormatError(msg.str()); alpar@209: } alpar@209: maps.insert(std::make_pair(map, index)); alpar@209: ++index; alpar@209: } alpar@209: alpar@209: for (int i = 0; i < static_cast(_node_maps.size()); ++i) { alpar@209: std::map::iterator jt = alpar@209: maps.find(_node_maps[i].first); alpar@209: if (jt == maps.end()) { alpar@209: std::ostringstream msg; kpeter@291: msg << "Map not found: " << _node_maps[i].first; deba@290: throw FormatError(msg.str()); alpar@209: } alpar@209: map_index[i] = jt->second; alpar@209: } alpar@209: alpar@209: { alpar@209: std::map::iterator jt = maps.find("label"); alpar@209: if (jt != maps.end()) { alpar@209: label_index = jt->second; alpar@209: } else { alpar@209: label_index = -1; alpar@209: } alpar@209: } alpar@209: map_num = maps.size(); deba@127: } deba@127: deba@127: while (readLine() && line >> c && c != '@') { alpar@209: line.putback(c); alpar@209: alpar@209: std::vector tokens(map_num); alpar@209: for (int i = 0; i < map_num; ++i) { alpar@209: if (!_reader_bits::readToken(line, tokens[i])) { alpar@209: std::ostringstream msg; alpar@209: msg << "Column not found (" << i + 1 << ")"; deba@290: throw FormatError(msg.str()); alpar@209: } alpar@209: } alpar@209: if (line >> std::ws >> c) kpeter@291: throw FormatError("Extra character at the end of line"); alpar@209: alpar@209: Node n; alpar@209: if (!_use_nodes) { alpar@209: n = _digraph.addNode(); alpar@209: if (label_index != -1) alpar@209: _node_index.insert(std::make_pair(tokens[label_index], n)); alpar@209: } else { alpar@209: if (label_index == -1) kpeter@291: throw FormatError("Label map not found"); alpar@209: typename std::map::iterator it = alpar@209: _node_index.find(tokens[label_index]); alpar@209: if (it == _node_index.end()) { alpar@209: std::ostringstream msg; alpar@209: msg << "Node with label not found: " << tokens[label_index]; deba@290: throw FormatError(msg.str()); alpar@209: } alpar@209: n = it->second; alpar@209: } alpar@209: alpar@209: for (int i = 0; i < static_cast(_node_maps.size()); ++i) { alpar@209: _node_maps[i].second->set(n, tokens[map_index[i]]); alpar@209: } deba@127: deba@127: } deba@127: if (readSuccess()) { alpar@209: line.putback(c); deba@127: } deba@127: } deba@127: deba@127: void readArcs() { deba@127: deba@127: std::vector map_index(_arc_maps.size()); deba@127: int map_num, label_index; deba@127: deba@186: char c; deba@186: if (!readLine() || !(line >> c) || c == '@') { alpar@209: if (readSuccess() && line) line.putback(c); alpar@209: if (!_arc_maps.empty()) deba@290: throw FormatError("Cannot find map names"); alpar@209: return; deba@186: } deba@186: line.putback(c); alpar@209: deba@127: { alpar@209: std::map maps; alpar@209: alpar@209: std::string map; alpar@209: int index = 0; alpar@209: while (_reader_bits::readToken(line, map)) { alpar@949: if(map == "-") { alpar@949: if(index!=0) alpar@949: throw FormatError("'-' is not allowed as a map name"); alpar@949: else if (line >> std::ws >> c) alpar@949: throw FormatError("Extra character at the end of line"); alpar@949: else break; alpar@949: } alpar@209: if (maps.find(map) != maps.end()) { alpar@209: std::ostringstream msg; alpar@209: msg << "Multiple occurence of arc map: " << map; deba@290: throw FormatError(msg.str()); alpar@209: } alpar@209: maps.insert(std::make_pair(map, index)); alpar@209: ++index; alpar@209: } alpar@209: alpar@209: for (int i = 0; i < static_cast(_arc_maps.size()); ++i) { alpar@209: std::map::iterator jt = alpar@209: maps.find(_arc_maps[i].first); alpar@209: if (jt == maps.end()) { alpar@209: std::ostringstream msg; kpeter@291: msg << "Map not found: " << _arc_maps[i].first; deba@290: throw FormatError(msg.str()); alpar@209: } alpar@209: map_index[i] = jt->second; alpar@209: } alpar@209: alpar@209: { alpar@209: std::map::iterator jt = maps.find("label"); alpar@209: if (jt != maps.end()) { alpar@209: label_index = jt->second; alpar@209: } else { alpar@209: label_index = -1; alpar@209: } alpar@209: } alpar@209: map_num = maps.size(); deba@127: } deba@127: deba@127: while (readLine() && line >> c && c != '@') { alpar@209: line.putback(c); alpar@209: alpar@209: std::string source_token; alpar@209: std::string target_token; alpar@209: alpar@209: if (!_reader_bits::readToken(line, source_token)) deba@290: throw FormatError("Source not found"); alpar@209: alpar@209: if (!_reader_bits::readToken(line, target_token)) deba@290: throw FormatError("Target not found"); alpar@209: alpar@209: std::vector tokens(map_num); alpar@209: for (int i = 0; i < map_num; ++i) { alpar@209: if (!_reader_bits::readToken(line, tokens[i])) { alpar@209: std::ostringstream msg; alpar@209: msg << "Column not found (" << i + 1 << ")"; deba@290: throw FormatError(msg.str()); alpar@209: } alpar@209: } alpar@209: if (line >> std::ws >> c) kpeter@291: throw FormatError("Extra character at the end of line"); alpar@209: alpar@209: Arc a; alpar@209: if (!_use_arcs) { deba@127: deba@127: typename NodeIndex::iterator it; alpar@209: deba@127: it = _node_index.find(source_token); deba@127: if (it == _node_index.end()) { deba@127: std::ostringstream msg; deba@127: msg << "Item not found: " << source_token; deba@290: throw FormatError(msg.str()); deba@127: } deba@127: Node source = it->second; deba@127: deba@127: it = _node_index.find(target_token); alpar@209: if (it == _node_index.end()) { alpar@209: std::ostringstream msg; deba@127: msg << "Item not found: " << target_token; deba@290: throw FormatError(msg.str()); alpar@209: } alpar@209: Node target = it->second; alpar@209: alpar@209: a = _digraph.addArc(source, target); alpar@209: if (label_index != -1) alpar@209: _arc_index.insert(std::make_pair(tokens[label_index], a)); alpar@209: } else { alpar@209: if (label_index == -1) kpeter@291: throw FormatError("Label map not found"); alpar@209: typename std::map::iterator it = alpar@209: _arc_index.find(tokens[label_index]); alpar@209: if (it == _arc_index.end()) { alpar@209: std::ostringstream msg; alpar@209: msg << "Arc with label not found: " << tokens[label_index]; deba@290: throw FormatError(msg.str()); alpar@209: } alpar@209: a = it->second; alpar@209: } alpar@209: alpar@209: for (int i = 0; i < static_cast(_arc_maps.size()); ++i) { alpar@209: _arc_maps[i].second->set(a, tokens[map_index[i]]); alpar@209: } deba@127: deba@127: } deba@127: if (readSuccess()) { alpar@209: line.putback(c); deba@127: } deba@127: } deba@127: deba@127: void readAttributes() { deba@127: deba@127: std::set read_attr; deba@127: deba@127: char c; deba@127: while (readLine() && line >> c && c != '@') { alpar@209: line.putback(c); alpar@209: alpar@209: std::string attr, token; alpar@209: if (!_reader_bits::readToken(line, attr)) deba@290: throw FormatError("Attribute name not found"); alpar@209: if (!_reader_bits::readToken(line, token)) deba@290: throw FormatError("Attribute value not found"); alpar@209: if (line >> c) kpeter@291: throw FormatError("Extra character at the end of line"); alpar@209: alpar@209: { alpar@209: std::set::iterator it = read_attr.find(attr); alpar@209: if (it != read_attr.end()) { alpar@209: std::ostringstream msg; kpeter@291: msg << "Multiple occurence of attribute: " << attr; deba@290: throw FormatError(msg.str()); alpar@209: } alpar@209: read_attr.insert(attr); alpar@209: } alpar@209: alpar@209: { alpar@209: typename Attributes::iterator it = _attributes.lower_bound(attr); alpar@209: while (it != _attributes.end() && it->first == attr) { alpar@209: it->second->set(token); alpar@209: ++it; alpar@209: } alpar@209: } deba@127: deba@127: } deba@127: if (readSuccess()) { alpar@209: line.putback(c); deba@127: } deba@127: for (typename Attributes::iterator it = _attributes.begin(); alpar@209: it != _attributes.end(); ++it) { alpar@209: if (read_attr.find(it->first) == read_attr.end()) { alpar@209: std::ostringstream msg; kpeter@291: msg << "Attribute not found: " << it->first; deba@290: throw FormatError(msg.str()); alpar@209: } deba@127: } deba@127: } deba@127: deba@127: public: alpar@156: kpeter@584: /// \name Execution of the Reader alpar@156: /// @{ alpar@156: alpar@156: /// \brief Start the batch processing alpar@156: /// alpar@156: /// This function starts the batch processing deba@127: void run() { deba@127: LEMON_ASSERT(_is != 0, "This reader assigned to an other reader"); alpar@209: deba@188: bool nodes_done = _skip_nodes; deba@188: bool arcs_done = _skip_arcs; deba@127: bool attributes_done = false; deba@127: alpar@209: line_num = 0; deba@127: readLine(); deba@172: skipSection(); deba@127: deba@127: while (readSuccess()) { alpar@209: try { alpar@209: char c; alpar@209: std::string section, caption; alpar@209: line >> c; alpar@209: _reader_bits::readToken(line, section); alpar@209: _reader_bits::readToken(line, caption); alpar@209: alpar@209: if (line >> c) kpeter@291: throw FormatError("Extra character at the end of line"); alpar@209: alpar@209: if (section == "nodes" && !nodes_done) { alpar@209: if (_nodes_caption.empty() || _nodes_caption == caption) { alpar@209: readNodes(); alpar@209: nodes_done = true; alpar@209: } alpar@209: } else if ((section == "arcs" || section == "edges") && alpar@209: !arcs_done) { alpar@209: if (_arcs_caption.empty() || _arcs_caption == caption) { alpar@209: readArcs(); alpar@209: arcs_done = true; alpar@209: } alpar@209: } else if (section == "attributes" && !attributes_done) { alpar@209: if (_attributes_caption.empty() || _attributes_caption == caption) { alpar@209: readAttributes(); alpar@209: attributes_done = true; alpar@209: } alpar@209: } else { alpar@209: readLine(); alpar@209: skipSection(); alpar@209: } deba@290: } catch (FormatError& error) { alpar@209: error.line(line_num); deba@290: error.file(_filename); alpar@209: throw; alpar@209: } deba@127: } deba@127: deba@127: if (!nodes_done) { deba@290: throw FormatError("Section @nodes not found"); deba@127: } deba@127: deba@127: if (!arcs_done) { deba@290: throw FormatError("Section @arcs not found"); deba@127: } deba@127: deba@127: if (!attributes_done && !_attributes.empty()) { deba@290: throw FormatError("Section @attributes not found"); deba@127: } deba@127: deba@127: } alpar@156: alpar@156: /// @} alpar@209: deba@127: }; deba@598: deba@598: /// \ingroup lemon_io deba@598: /// deba@598: /// \brief Return a \ref DigraphReader class deba@598: /// deba@598: /// This function just returns a \ref DigraphReader class. deba@598: /// deba@598: /// With this function a digraph can be read from an deba@598: /// \ref lgf-format "LGF" file or input stream with several maps and deba@598: /// attributes. For example, there is network flow problem on a deba@598: /// digraph, i.e. a digraph with a \e capacity map on the arcs and deba@598: /// \e source and \e target nodes. This digraph can be read with the deba@598: /// following code: deba@598: /// deba@598: ///\code deba@598: ///ListDigraph digraph; deba@598: ///ListDigraph::ArcMap cm(digraph); deba@598: ///ListDigraph::Node src, trg; deba@598: ///digraphReader(digraph, std::cin). deba@598: /// arcMap("capacity", cap). deba@598: /// node("source", src). deba@598: /// node("target", trg). deba@598: /// run(); deba@598: ///\endcode deba@598: /// deba@598: /// For a complete documentation, please see the \ref DigraphReader deba@598: /// class documentation. deba@598: /// \warning Don't forget to put the \ref DigraphReader::run() "run()" deba@598: /// to the end of the parameter list. deba@598: /// \relates DigraphReader deba@598: /// \sa digraphReader(TDGR& digraph, const std::string& fn) deba@598: /// \sa digraphReader(TDGR& digraph, const char* fn) deba@598: template deba@598: DigraphReader digraphReader(TDGR& digraph, std::istream& is) { deba@598: DigraphReader tmp(digraph, is); deba@598: return tmp; deba@598: } deba@127: kpeter@498: /// \brief Return a \ref DigraphReader class kpeter@498: /// kpeter@498: /// This function just returns a \ref DigraphReader class. kpeter@498: /// \relates DigraphReader deba@598: /// \sa digraphReader(TDGR& digraph, std::istream& is) deba@598: template deba@598: DigraphReader digraphReader(TDGR& digraph, const std::string& fn) { deba@598: DigraphReader tmp(digraph, fn); kpeter@498: return tmp; kpeter@498: } kpeter@498: kpeter@498: /// \brief Return a \ref DigraphReader class kpeter@498: /// kpeter@498: /// This function just returns a \ref DigraphReader class. kpeter@498: /// \relates DigraphReader deba@598: /// \sa digraphReader(TDGR& digraph, std::istream& is) deba@598: template deba@598: DigraphReader digraphReader(TDGR& digraph, const char* fn) { deba@598: DigraphReader tmp(digraph, fn); kpeter@498: return tmp; kpeter@498: } kpeter@498: deba@598: template ladanyi@303: class GraphReader; kpeter@498: deba@598: template deba@598: GraphReader graphReader(TGR& graph, std::istream& is = std::cin); deba@598: template deba@598: GraphReader graphReader(TGR& graph, const std::string& fn); deba@598: template deba@598: GraphReader graphReader(TGR& graph, const char *fn); deba@165: deba@165: /// \ingroup lemon_io alpar@209: /// kpeter@192: /// \brief \ref lgf-format "LGF" reader for undirected graphs deba@165: /// deba@165: /// This utility reads an \ref lgf-format "LGF" file. kpeter@192: /// kpeter@192: /// It can be used almost the same way as \c DigraphReader. kpeter@192: /// The only difference is that this class can handle edges and kpeter@192: /// edge maps as well as arcs and arc maps. deba@201: /// deba@201: /// The columns in the \c \@edges (or \c \@arcs) section are the deba@201: /// edge maps. However, if there are two maps with the same name deba@201: /// prefixed with \c '+' and \c '-', then these can be read into an deba@201: /// arc map. Similarly, an attribute can be read into an arc, if deba@201: /// it's value is an edge label prefixed with \c '+' or \c '-'. kpeter@559: template deba@165: class GraphReader { deba@165: public: deba@165: kpeter@559: typedef GR Graph; alpar@209: deba@165: private: deba@165: deba@598: TEMPLATE_GRAPH_TYPEDEFS(GR); kpeter@498: deba@165: std::istream* _is; deba@165: bool local_is; deba@290: std::string _filename; deba@165: deba@598: GR& _graph; deba@165: deba@165: std::string _nodes_caption; deba@165: std::string _edges_caption; deba@165: std::string _attributes_caption; deba@165: deba@165: typedef std::map NodeIndex; deba@165: NodeIndex _node_index; deba@165: typedef std::map EdgeIndex; deba@165: EdgeIndex _edge_index; alpar@209: alpar@209: typedef std::vector*> > NodeMaps; alpar@209: NodeMaps _node_maps; deba@165: deba@165: typedef std::vector*> > EdgeMaps; deba@165: EdgeMaps _edge_maps; deba@165: alpar@209: typedef std::multimap deba@165: Attributes; deba@165: Attributes _attributes; deba@165: deba@165: bool _use_nodes; deba@165: bool _use_edges; deba@165: deba@188: bool _skip_nodes; deba@188: bool _skip_edges; deba@188: deba@165: int line_num; deba@165: std::istringstream line; deba@165: deba@165: public: deba@165: deba@165: /// \brief Constructor deba@165: /// kpeter@192: /// Construct an undirected graph reader, which reads from the given deba@165: /// input stream. deba@598: GraphReader(GR& graph, std::istream& is = std::cin) deba@165: : _is(&is), local_is(false), _graph(graph), alpar@209: _use_nodes(false), _use_edges(false), alpar@209: _skip_nodes(false), _skip_edges(false) {} deba@165: deba@165: /// \brief Constructor deba@165: /// kpeter@192: /// Construct an undirected graph reader, which reads from the given deba@165: /// file. deba@598: GraphReader(GR& graph, const std::string& fn) deba@290: : _is(new std::ifstream(fn.c_str())), local_is(true), deba@290: _filename(fn), _graph(graph), kpeter@212: _use_nodes(false), _use_edges(false), deba@290: _skip_nodes(false), _skip_edges(false) { deba@295: if (!(*_is)) { deba@295: delete _is; deba@295: throw IoError("Cannot open file", fn); deba@295: } deba@290: } alpar@209: deba@165: /// \brief Constructor deba@165: /// kpeter@192: /// Construct an undirected graph reader, which reads from the given deba@165: /// file. deba@598: GraphReader(GR& graph, const char* fn) deba@290: : _is(new std::ifstream(fn)), local_is(true), deba@290: _filename(fn), _graph(graph), kpeter@212: _use_nodes(false), _use_edges(false), deba@290: _skip_nodes(false), _skip_edges(false) { deba@295: if (!(*_is)) { deba@295: delete _is; deba@295: throw IoError("Cannot open file", fn); deba@295: } deba@290: } deba@165: deba@165: /// \brief Destructor deba@165: ~GraphReader() { alpar@209: for (typename NodeMaps::iterator it = _node_maps.begin(); alpar@209: it != _node_maps.end(); ++it) { alpar@209: delete it->second; deba@165: } deba@165: alpar@209: for (typename EdgeMaps::iterator it = _edge_maps.begin(); alpar@209: it != _edge_maps.end(); ++it) { alpar@209: delete it->second; deba@165: } deba@165: alpar@209: for (typename Attributes::iterator it = _attributes.begin(); alpar@209: it != _attributes.end(); ++it) { alpar@209: delete it->second; deba@165: } deba@165: deba@165: if (local_is) { alpar@209: delete _is; deba@165: } deba@165: deba@165: } deba@165: deba@165: private: deba@598: template deba@598: friend GraphReader graphReader(TGR& graph, std::istream& is); deba@598: template deba@598: friend GraphReader graphReader(TGR& graph, const std::string& fn); deba@598: template deba@598: friend GraphReader graphReader(TGR& graph, const char *fn); alpar@209: alpar@209: GraphReader(GraphReader& other) deba@190: : _is(other._is), local_is(other.local_is), _graph(other._graph), alpar@209: _use_nodes(other._use_nodes), _use_edges(other._use_edges), alpar@209: _skip_nodes(other._skip_nodes), _skip_edges(other._skip_edges) { deba@190: deba@190: other._is = 0; deba@190: other.local_is = false; alpar@209: deba@190: _node_index.swap(other._node_index); deba@190: _edge_index.swap(other._edge_index); deba@190: deba@190: _node_maps.swap(other._node_maps); deba@190: _edge_maps.swap(other._edge_maps); deba@190: _attributes.swap(other._attributes); deba@190: deba@190: _nodes_caption = other._nodes_caption; deba@190: _edges_caption = other._edges_caption; deba@190: _attributes_caption = other._attributes_caption; deba@190: deba@190: } deba@190: deba@165: GraphReader& operator=(const GraphReader&); deba@165: deba@165: public: deba@165: kpeter@584: /// \name Reading Rules deba@165: /// @{ alpar@209: deba@165: /// \brief Node map reading rule deba@165: /// deba@165: /// Add a node map reading rule to the reader. deba@165: template deba@165: GraphReader& nodeMap(const std::string& caption, Map& map) { deba@165: checkConcept, Map>(); alpar@209: _reader_bits::MapStorageBase* storage = alpar@209: new _reader_bits::MapStorage(map); deba@165: _node_maps.push_back(std::make_pair(caption, storage)); deba@165: return *this; deba@165: } deba@165: deba@165: /// \brief Node map reading rule deba@165: /// deba@165: /// Add a node map reading rule with specialized converter to the deba@165: /// reader. deba@165: template alpar@209: GraphReader& nodeMap(const std::string& caption, Map& map, alpar@209: const Converter& converter = Converter()) { deba@165: checkConcept, Map>(); alpar@209: _reader_bits::MapStorageBase* storage = alpar@209: new _reader_bits::MapStorage(map, converter); deba@165: _node_maps.push_back(std::make_pair(caption, storage)); deba@165: return *this; deba@165: } deba@165: deba@165: /// \brief Edge map reading rule deba@165: /// deba@165: /// Add an edge map reading rule to the reader. deba@165: template deba@165: GraphReader& edgeMap(const std::string& caption, Map& map) { deba@165: checkConcept, Map>(); alpar@209: _reader_bits::MapStorageBase* storage = alpar@209: new _reader_bits::MapStorage(map); deba@165: _edge_maps.push_back(std::make_pair(caption, storage)); deba@165: return *this; deba@165: } deba@165: deba@165: /// \brief Edge map reading rule deba@165: /// deba@165: /// Add an edge map reading rule with specialized converter to the deba@165: /// reader. deba@165: template alpar@209: GraphReader& edgeMap(const std::string& caption, Map& map, alpar@209: const Converter& converter = Converter()) { deba@165: checkConcept, Map>(); alpar@209: _reader_bits::MapStorageBase* storage = alpar@209: new _reader_bits::MapStorage(map, converter); deba@165: _edge_maps.push_back(std::make_pair(caption, storage)); deba@165: return *this; deba@165: } deba@165: deba@165: /// \brief Arc map reading rule deba@165: /// deba@165: /// Add an arc map reading rule to the reader. deba@165: template deba@165: GraphReader& arcMap(const std::string& caption, Map& map) { deba@165: checkConcept, Map>(); alpar@209: _reader_bits::MapStorageBase* forward_storage = alpar@209: new _reader_bits::GraphArcMapStorage(_graph, map); deba@165: _edge_maps.push_back(std::make_pair('+' + caption, forward_storage)); alpar@209: _reader_bits::MapStorageBase* backward_storage = deba@598: new _reader_bits::GraphArcMapStorage(_graph, map); deba@165: _edge_maps.push_back(std::make_pair('-' + caption, backward_storage)); deba@165: return *this; deba@165: } deba@165: deba@165: /// \brief Arc map reading rule deba@165: /// deba@165: /// Add an arc map reading rule with specialized converter to the deba@165: /// reader. deba@165: template alpar@209: GraphReader& arcMap(const std::string& caption, Map& map, alpar@209: const Converter& converter = Converter()) { deba@165: checkConcept, Map>(); alpar@209: _reader_bits::MapStorageBase* forward_storage = deba@598: new _reader_bits::GraphArcMapStorage alpar@209: (_graph, map, converter); deba@165: _edge_maps.push_back(std::make_pair('+' + caption, forward_storage)); alpar@209: _reader_bits::MapStorageBase* backward_storage = deba@598: new _reader_bits::GraphArcMapStorage alpar@209: (_graph, map, converter); deba@165: _edge_maps.push_back(std::make_pair('-' + caption, backward_storage)); deba@165: return *this; deba@165: } deba@165: deba@165: /// \brief Attribute reading rule deba@165: /// deba@165: /// Add an attribute reading rule to the reader. deba@165: template deba@165: GraphReader& attribute(const std::string& caption, Value& value) { alpar@209: _reader_bits::ValueStorageBase* storage = alpar@209: new _reader_bits::ValueStorage(value); deba@165: _attributes.insert(std::make_pair(caption, storage)); deba@165: return *this; deba@165: } deba@165: deba@165: /// \brief Attribute reading rule deba@165: /// deba@165: /// Add an attribute reading rule with specialized converter to the deba@165: /// reader. deba@165: template alpar@209: GraphReader& attribute(const std::string& caption, Value& value, alpar@209: const Converter& converter = Converter()) { alpar@209: _reader_bits::ValueStorageBase* storage = alpar@209: new _reader_bits::ValueStorage(value, converter); deba@165: _attributes.insert(std::make_pair(caption, storage)); deba@165: return *this; deba@165: } deba@165: deba@165: /// \brief Node reading rule deba@165: /// deba@165: /// Add a node reading rule to reader. deba@165: GraphReader& node(const std::string& caption, Node& node) { deba@165: typedef _reader_bits::MapLookUpConverter Converter; deba@165: Converter converter(_node_index); alpar@209: _reader_bits::ValueStorageBase* storage = alpar@209: new _reader_bits::ValueStorage(node, converter); deba@165: _attributes.insert(std::make_pair(caption, storage)); deba@165: return *this; deba@165: } deba@165: deba@165: /// \brief Edge reading rule deba@165: /// deba@165: /// Add an edge reading rule to reader. deba@165: GraphReader& edge(const std::string& caption, Edge& edge) { deba@165: typedef _reader_bits::MapLookUpConverter Converter; deba@165: Converter converter(_edge_index); alpar@209: _reader_bits::ValueStorageBase* storage = alpar@209: new _reader_bits::ValueStorage(edge, converter); deba@165: _attributes.insert(std::make_pair(caption, storage)); deba@165: return *this; deba@165: } deba@165: deba@165: /// \brief Arc reading rule deba@165: /// deba@165: /// Add an arc reading rule to reader. deba@165: GraphReader& arc(const std::string& caption, Arc& arc) { deba@598: typedef _reader_bits::GraphArcLookUpConverter Converter; deba@165: Converter converter(_graph, _edge_index); alpar@209: _reader_bits::ValueStorageBase* storage = alpar@209: new _reader_bits::ValueStorage(arc, converter); deba@165: _attributes.insert(std::make_pair(caption, storage)); deba@165: return *this; deba@165: } deba@165: deba@165: /// @} deba@165: kpeter@584: /// \name Select Section by Name deba@165: /// @{ deba@165: deba@165: /// \brief Set \c \@nodes section to be read deba@165: /// kpeter@192: /// Set \c \@nodes section to be read. deba@165: GraphReader& nodes(const std::string& caption) { deba@165: _nodes_caption = caption; deba@165: return *this; deba@165: } deba@165: deba@165: /// \brief Set \c \@edges section to be read deba@165: /// kpeter@192: /// Set \c \@edges section to be read. deba@165: GraphReader& edges(const std::string& caption) { deba@165: _edges_caption = caption; deba@165: return *this; deba@165: } deba@165: deba@165: /// \brief Set \c \@attributes section to be read deba@165: /// kpeter@192: /// Set \c \@attributes section to be read. deba@165: GraphReader& attributes(const std::string& caption) { deba@165: _attributes_caption = caption; deba@165: return *this; deba@165: } deba@165: deba@165: /// @} deba@165: kpeter@584: /// \name Using Previously Constructed Node or Edge Set deba@165: /// @{ deba@165: deba@165: /// \brief Use previously constructed node set deba@165: /// deba@165: /// Use previously constructed node set, and specify the node deba@165: /// label map. deba@165: template deba@165: GraphReader& useNodes(const Map& map) { deba@165: checkConcept, Map>(); alpar@209: LEMON_ASSERT(!_use_nodes, "Multiple usage of useNodes() member"); deba@165: _use_nodes = true; deba@165: _writer_bits::DefaultConverter converter; deba@165: for (NodeIt n(_graph); n != INVALID; ++n) { alpar@209: _node_index.insert(std::make_pair(converter(map[n]), n)); deba@165: } deba@165: return *this; deba@165: } deba@165: deba@165: /// \brief Use previously constructed node set deba@165: /// deba@165: /// Use previously constructed node set, and specify the node deba@165: /// label map and a functor which converts the label map values to kpeter@192: /// \c std::string. deba@165: template alpar@209: GraphReader& useNodes(const Map& map, alpar@209: const Converter& converter = Converter()) { deba@165: checkConcept, Map>(); alpar@209: LEMON_ASSERT(!_use_nodes, "Multiple usage of useNodes() member"); deba@165: _use_nodes = true; deba@165: for (NodeIt n(_graph); n != INVALID; ++n) { alpar@209: _node_index.insert(std::make_pair(converter(map[n]), n)); deba@165: } deba@165: return *this; deba@165: } deba@165: deba@165: /// \brief Use previously constructed edge set deba@165: /// deba@165: /// Use previously constructed edge set, and specify the edge deba@165: /// label map. deba@165: template deba@165: GraphReader& useEdges(const Map& map) { deba@165: checkConcept, Map>(); deba@165: LEMON_ASSERT(!_use_edges, "Multiple usage of useEdges() member"); deba@165: _use_edges = true; deba@165: _writer_bits::DefaultConverter converter; deba@165: for (EdgeIt a(_graph); a != INVALID; ++a) { alpar@209: _edge_index.insert(std::make_pair(converter(map[a]), a)); deba@165: } deba@165: return *this; deba@165: } deba@165: deba@165: /// \brief Use previously constructed edge set deba@165: /// deba@165: /// Use previously constructed edge set, and specify the edge deba@165: /// label map and a functor which converts the label map values to kpeter@192: /// \c std::string. deba@165: template alpar@209: GraphReader& useEdges(const Map& map, alpar@209: const Converter& converter = Converter()) { deba@165: checkConcept, Map>(); alpar@209: LEMON_ASSERT(!_use_edges, "Multiple usage of useEdges() member"); deba@165: _use_edges = true; deba@165: for (EdgeIt a(_graph); a != INVALID; ++a) { alpar@209: _edge_index.insert(std::make_pair(converter(map[a]), a)); deba@165: } deba@165: return *this; deba@165: } deba@165: kpeter@192: /// \brief Skip the reading of node section deba@188: /// deba@188: /// Omit the reading of the node section. This implies that each node kpeter@192: /// map reading rule will be abandoned, and the nodes of the graph deba@188: /// will not be constructed, which usually cause that the edge set deba@188: /// could not be read due to lack of node name kpeter@192: /// could not be read due to lack of node name resolving. kpeter@192: /// Therefore \c skipEdges() function should also be used, or kpeter@192: /// \c useNodes() should be used to specify the label of the nodes. deba@188: GraphReader& skipNodes() { alpar@209: LEMON_ASSERT(!_skip_nodes, "Skip nodes already set"); deba@188: _skip_nodes = true; deba@188: return *this; deba@188: } deba@188: kpeter@192: /// \brief Skip the reading of edge section deba@188: /// deba@188: /// Omit the reading of the edge section. This implies that each edge kpeter@192: /// map reading rule will be abandoned, and the edges of the graph deba@188: /// will not be constructed. deba@188: GraphReader& skipEdges() { alpar@209: LEMON_ASSERT(!_skip_edges, "Skip edges already set"); deba@188: _skip_edges = true; deba@188: return *this; deba@188: } deba@188: deba@165: /// @} deba@165: deba@165: private: deba@165: deba@165: bool readLine() { deba@165: std::string str; deba@165: while(++line_num, std::getline(*_is, str)) { alpar@209: line.clear(); line.str(str); alpar@209: char c; alpar@209: if (line >> std::ws >> c && c != '#') { alpar@209: line.putback(c); alpar@209: return true; alpar@209: } deba@165: } deba@165: return false; deba@165: } deba@165: deba@165: bool readSuccess() { deba@165: return static_cast(*_is); deba@165: } alpar@209: deba@165: void skipSection() { deba@165: char c; deba@165: while (readSuccess() && line >> c && c != '@') { alpar@209: readLine(); deba@165: } deba@427: if (readSuccess()) { deba@427: line.putback(c); deba@427: } deba@165: } deba@165: deba@165: void readNodes() { deba@165: deba@165: std::vector map_index(_node_maps.size()); deba@165: int map_num, label_index; deba@165: deba@186: char c; deba@186: if (!readLine() || !(line >> c) || c == '@') { alpar@209: if (readSuccess() && line) line.putback(c); alpar@209: if (!_node_maps.empty()) deba@290: throw FormatError("Cannot find map names"); alpar@209: return; deba@186: } deba@186: line.putback(c); alpar@209: deba@165: { alpar@209: std::map maps; alpar@209: alpar@209: std::string map; alpar@209: int index = 0; alpar@209: while (_reader_bits::readToken(line, map)) { alpar@209: if (maps.find(map) != maps.end()) { alpar@209: std::ostringstream msg; alpar@209: msg << "Multiple occurence of node map: " << map; deba@290: throw FormatError(msg.str()); alpar@209: } alpar@209: maps.insert(std::make_pair(map, index)); alpar@209: ++index; alpar@209: } alpar@209: alpar@209: for (int i = 0; i < static_cast(_node_maps.size()); ++i) { alpar@209: std::map::iterator jt = alpar@209: maps.find(_node_maps[i].first); alpar@209: if (jt == maps.end()) { alpar@209: std::ostringstream msg; kpeter@291: msg << "Map not found: " << _node_maps[i].first; deba@290: throw FormatError(msg.str()); alpar@209: } alpar@209: map_index[i] = jt->second; alpar@209: } alpar@209: alpar@209: { alpar@209: std::map::iterator jt = maps.find("label"); alpar@209: if (jt != maps.end()) { alpar@209: label_index = jt->second; alpar@209: } else { alpar@209: label_index = -1; alpar@209: } alpar@209: } alpar@209: map_num = maps.size(); deba@165: } deba@165: deba@165: while (readLine() && line >> c && c != '@') { alpar@209: line.putback(c); alpar@209: alpar@209: std::vector tokens(map_num); alpar@209: for (int i = 0; i < map_num; ++i) { alpar@209: if (!_reader_bits::readToken(line, tokens[i])) { alpar@209: std::ostringstream msg; alpar@209: msg << "Column not found (" << i + 1 << ")"; deba@290: throw FormatError(msg.str()); alpar@209: } alpar@209: } alpar@209: if (line >> std::ws >> c) kpeter@291: throw FormatError("Extra character at the end of line"); alpar@209: alpar@209: Node n; alpar@209: if (!_use_nodes) { alpar@209: n = _graph.addNode(); alpar@209: if (label_index != -1) alpar@209: _node_index.insert(std::make_pair(tokens[label_index], n)); alpar@209: } else { alpar@209: if (label_index == -1) kpeter@291: throw FormatError("Label map not found"); alpar@209: typename std::map::iterator it = alpar@209: _node_index.find(tokens[label_index]); alpar@209: if (it == _node_index.end()) { alpar@209: std::ostringstream msg; alpar@209: msg << "Node with label not found: " << tokens[label_index]; deba@290: throw FormatError(msg.str()); alpar@209: } alpar@209: n = it->second; alpar@209: } alpar@209: alpar@209: for (int i = 0; i < static_cast(_node_maps.size()); ++i) { alpar@209: _node_maps[i].second->set(n, tokens[map_index[i]]); alpar@209: } deba@165: deba@165: } deba@165: if (readSuccess()) { alpar@209: line.putback(c); deba@165: } deba@165: } deba@165: deba@165: void readEdges() { deba@165: deba@165: std::vector map_index(_edge_maps.size()); deba@165: int map_num, label_index; deba@165: deba@186: char c; deba@186: if (!readLine() || !(line >> c) || c == '@') { alpar@209: if (readSuccess() && line) line.putback(c); alpar@209: if (!_edge_maps.empty()) deba@290: throw FormatError("Cannot find map names"); alpar@209: return; deba@186: } deba@186: line.putback(c); alpar@209: deba@165: { alpar@209: std::map maps; alpar@209: alpar@209: std::string map; alpar@209: int index = 0; alpar@209: while (_reader_bits::readToken(line, map)) { alpar@949: if(map == "-") { alpar@949: if(index!=0) alpar@949: throw FormatError("'-' is not allowed as a map name"); alpar@949: else if (line >> std::ws >> c) alpar@949: throw FormatError("Extra character at the end of line"); alpar@949: else break; alpar@949: } alpar@209: if (maps.find(map) != maps.end()) { alpar@209: std::ostringstream msg; alpar@209: msg << "Multiple occurence of edge map: " << map; deba@290: throw FormatError(msg.str()); alpar@209: } alpar@209: maps.insert(std::make_pair(map, index)); alpar@209: ++index; alpar@209: } alpar@209: alpar@209: for (int i = 0; i < static_cast(_edge_maps.size()); ++i) { alpar@209: std::map::iterator jt = alpar@209: maps.find(_edge_maps[i].first); alpar@209: if (jt == maps.end()) { alpar@209: std::ostringstream msg; kpeter@291: msg << "Map not found: " << _edge_maps[i].first; deba@290: throw FormatError(msg.str()); alpar@209: } alpar@209: map_index[i] = jt->second; alpar@209: } alpar@209: alpar@209: { alpar@209: std::map::iterator jt = maps.find("label"); alpar@209: if (jt != maps.end()) { alpar@209: label_index = jt->second; alpar@209: } else { alpar@209: label_index = -1; alpar@209: } alpar@209: } alpar@209: map_num = maps.size(); deba@165: } deba@165: deba@165: while (readLine() && line >> c && c != '@') { alpar@209: line.putback(c); alpar@209: alpar@209: std::string source_token; alpar@209: std::string target_token; alpar@209: alpar@209: if (!_reader_bits::readToken(line, source_token)) deba@290: throw FormatError("Node u not found"); alpar@209: alpar@209: if (!_reader_bits::readToken(line, target_token)) deba@290: throw FormatError("Node v not found"); alpar@209: alpar@209: std::vector tokens(map_num); alpar@209: for (int i = 0; i < map_num; ++i) { alpar@209: if (!_reader_bits::readToken(line, tokens[i])) { alpar@209: std::ostringstream msg; alpar@209: msg << "Column not found (" << i + 1 << ")"; deba@290: throw FormatError(msg.str()); alpar@209: } alpar@209: } alpar@209: if (line >> std::ws >> c) kpeter@291: throw FormatError("Extra character at the end of line"); alpar@209: alpar@209: Edge e; alpar@209: if (!_use_edges) { deba@165: deba@165: typename NodeIndex::iterator it; alpar@209: deba@165: it = _node_index.find(source_token); deba@165: if (it == _node_index.end()) { deba@165: std::ostringstream msg; deba@165: msg << "Item not found: " << source_token; deba@290: throw FormatError(msg.str()); deba@165: } deba@165: Node source = it->second; deba@165: deba@165: it = _node_index.find(target_token); alpar@209: if (it == _node_index.end()) { alpar@209: std::ostringstream msg; deba@165: msg << "Item not found: " << target_token; deba@290: throw FormatError(msg.str()); alpar@209: } alpar@209: Node target = it->second; alpar@209: alpar@209: e = _graph.addEdge(source, target); alpar@209: if (label_index != -1) alpar@209: _edge_index.insert(std::make_pair(tokens[label_index], e)); alpar@209: } else { alpar@209: if (label_index == -1) kpeter@291: throw FormatError("Label map not found"); alpar@209: typename std::map::iterator it = alpar@209: _edge_index.find(tokens[label_index]); alpar@209: if (it == _edge_index.end()) { alpar@209: std::ostringstream msg; alpar@209: msg << "Edge with label not found: " << tokens[label_index]; deba@290: throw FormatError(msg.str()); alpar@209: } alpar@209: e = it->second; alpar@209: } alpar@209: alpar@209: for (int i = 0; i < static_cast(_edge_maps.size()); ++i) { alpar@209: _edge_maps[i].second->set(e, tokens[map_index[i]]); alpar@209: } deba@165: deba@165: } deba@165: if (readSuccess()) { alpar@209: line.putback(c); deba@165: } deba@165: } deba@165: deba@165: void readAttributes() { deba@165: deba@165: std::set read_attr; deba@165: deba@165: char c; deba@165: while (readLine() && line >> c && c != '@') { alpar@209: line.putback(c); alpar@209: alpar@209: std::string attr, token; alpar@209: if (!_reader_bits::readToken(line, attr)) deba@290: throw FormatError("Attribute name not found"); alpar@209: if (!_reader_bits::readToken(line, token)) deba@290: throw FormatError("Attribute value not found"); alpar@209: if (line >> c) kpeter@291: throw FormatError("Extra character at the end of line"); alpar@209: alpar@209: { alpar@209: std::set::iterator it = read_attr.find(attr); alpar@209: if (it != read_attr.end()) { alpar@209: std::ostringstream msg; kpeter@291: msg << "Multiple occurence of attribute: " << attr; deba@290: throw FormatError(msg.str()); alpar@209: } alpar@209: read_attr.insert(attr); alpar@209: } alpar@209: alpar@209: { alpar@209: typename Attributes::iterator it = _attributes.lower_bound(attr); alpar@209: while (it != _attributes.end() && it->first == attr) { alpar@209: it->second->set(token); alpar@209: ++it; alpar@209: } alpar@209: } deba@165: deba@165: } deba@165: if (readSuccess()) { alpar@209: line.putback(c); deba@165: } deba@165: for (typename Attributes::iterator it = _attributes.begin(); alpar@209: it != _attributes.end(); ++it) { alpar@209: if (read_attr.find(it->first) == read_attr.end()) { alpar@209: std::ostringstream msg; kpeter@291: msg << "Attribute not found: " << it->first; deba@290: throw FormatError(msg.str()); alpar@209: } deba@165: } deba@165: } deba@165: deba@165: public: deba@165: kpeter@584: /// \name Execution of the Reader deba@165: /// @{ deba@165: deba@165: /// \brief Start the batch processing deba@165: /// deba@165: /// This function starts the batch processing deba@165: void run() { alpar@209: deba@165: LEMON_ASSERT(_is != 0, "This reader assigned to an other reader"); alpar@209: deba@188: bool nodes_done = _skip_nodes; deba@188: bool edges_done = _skip_edges; deba@165: bool attributes_done = false; deba@165: alpar@209: line_num = 0; deba@165: readLine(); deba@172: skipSection(); deba@165: deba@165: while (readSuccess()) { alpar@209: try { alpar@209: char c; alpar@209: std::string section, caption; alpar@209: line >> c; alpar@209: _reader_bits::readToken(line, section); alpar@209: _reader_bits::readToken(line, caption); alpar@209: alpar@209: if (line >> c) kpeter@291: throw FormatError("Extra character at the end of line"); alpar@209: alpar@209: if (section == "nodes" && !nodes_done) { alpar@209: if (_nodes_caption.empty() || _nodes_caption == caption) { alpar@209: readNodes(); alpar@209: nodes_done = true; alpar@209: } alpar@209: } else if ((section == "edges" || section == "arcs") && alpar@209: !edges_done) { alpar@209: if (_edges_caption.empty() || _edges_caption == caption) { alpar@209: readEdges(); alpar@209: edges_done = true; alpar@209: } alpar@209: } else if (section == "attributes" && !attributes_done) { alpar@209: if (_attributes_caption.empty() || _attributes_caption == caption) { alpar@209: readAttributes(); alpar@209: attributes_done = true; alpar@209: } alpar@209: } else { alpar@209: readLine(); alpar@209: skipSection(); alpar@209: } deba@290: } catch (FormatError& error) { alpar@209: error.line(line_num); deba@290: error.file(_filename); alpar@209: throw; alpar@209: } deba@165: } deba@165: deba@165: if (!nodes_done) { deba@290: throw FormatError("Section @nodes not found"); deba@165: } deba@165: deba@165: if (!edges_done) { deba@290: throw FormatError("Section @edges not found"); deba@165: } deba@165: deba@165: if (!attributes_done && !_attributes.empty()) { deba@290: throw FormatError("Section @attributes not found"); deba@165: } deba@165: deba@165: } deba@165: deba@165: /// @} alpar@209: deba@165: }; deba@165: deba@598: /// \ingroup lemon_io deba@598: /// deba@598: /// \brief Return a \ref GraphReader class deba@598: /// deba@598: /// This function just returns a \ref GraphReader class. deba@598: /// deba@598: /// With this function a graph can be read from an deba@598: /// \ref lgf-format "LGF" file or input stream with several maps and deba@598: /// attributes. For example, there is weighted matching problem on a deba@598: /// graph, i.e. a graph with a \e weight map on the edges. This deba@598: /// graph can be read with the following code: deba@598: /// deba@598: ///\code deba@598: ///ListGraph graph; deba@598: ///ListGraph::EdgeMap weight(graph); deba@598: ///graphReader(graph, std::cin). deba@598: /// edgeMap("weight", weight). deba@598: /// run(); deba@598: ///\endcode deba@598: /// deba@598: /// For a complete documentation, please see the \ref GraphReader deba@598: /// class documentation. deba@598: /// \warning Don't forget to put the \ref GraphReader::run() "run()" deba@598: /// to the end of the parameter list. deba@598: /// \relates GraphReader deba@598: /// \sa graphReader(TGR& graph, const std::string& fn) deba@598: /// \sa graphReader(TGR& graph, const char* fn) deba@598: template deba@598: GraphReader graphReader(TGR& graph, std::istream& is) { deba@598: GraphReader tmp(graph, is); deba@598: return tmp; deba@598: } deba@598: kpeter@498: /// \brief Return a \ref GraphReader class kpeter@498: /// kpeter@498: /// This function just returns a \ref GraphReader class. kpeter@498: /// \relates GraphReader deba@598: /// \sa graphReader(TGR& graph, std::istream& is) deba@598: template deba@598: GraphReader graphReader(TGR& graph, const std::string& fn) { deba@598: GraphReader tmp(graph, fn); kpeter@498: return tmp; kpeter@498: } kpeter@498: kpeter@498: /// \brief Return a \ref GraphReader class kpeter@498: /// kpeter@498: /// This function just returns a \ref GraphReader class. kpeter@498: /// \relates GraphReader deba@598: /// \sa graphReader(TGR& graph, std::istream& is) deba@598: template deba@598: GraphReader graphReader(TGR& graph, const char* fn) { deba@598: GraphReader tmp(graph, fn); kpeter@498: return tmp; kpeter@498: } kpeter@498: deba@190: class SectionReader; deba@190: deba@190: SectionReader sectionReader(std::istream& is); deba@190: SectionReader sectionReader(const std::string& fn); deba@190: SectionReader sectionReader(const char* fn); alpar@209: kpeter@192: /// \ingroup lemon_io kpeter@192: /// deba@189: /// \brief Section reader class deba@189: /// alpar@209: /// In the \ref lgf-format "LGF" file extra sections can be placed, kpeter@192: /// which contain any data in arbitrary format. Such sections can be alpar@209: /// read with this class. A reading rule can be added to the class kpeter@192: /// with two different functions. With the \c sectionLines() function a kpeter@192: /// functor can process the section line-by-line, while with the \c deba@189: /// sectionStream() member the section can be read from an input deba@189: /// stream. deba@189: class SectionReader { deba@189: private: alpar@209: deba@189: std::istream* _is; deba@189: bool local_is; deba@290: std::string _filename; deba@189: deba@189: typedef std::map Sections; deba@189: Sections _sections; deba@189: deba@189: int line_num; deba@189: std::istringstream line; deba@189: deba@189: public: deba@189: deba@189: /// \brief Constructor deba@189: /// deba@189: /// Construct a section reader, which reads from the given input deba@189: /// stream. alpar@209: SectionReader(std::istream& is) deba@189: : _is(&is), local_is(false) {} deba@189: deba@189: /// \brief Constructor deba@189: /// deba@189: /// Construct a section reader, which reads from the given file. alpar@209: SectionReader(const std::string& fn) deba@290: : _is(new std::ifstream(fn.c_str())), local_is(true), deba@290: _filename(fn) { deba@295: if (!(*_is)) { deba@295: delete _is; deba@295: throw IoError("Cannot open file", fn); deba@295: } deba@290: } alpar@209: deba@189: /// \brief Constructor deba@189: /// deba@189: /// Construct a section reader, which reads from the given file. alpar@209: SectionReader(const char* fn) deba@290: : _is(new std::ifstream(fn)), local_is(true), deba@290: _filename(fn) { deba@295: if (!(*_is)) { deba@295: delete _is; deba@295: throw IoError("Cannot open file", fn); deba@295: } deba@290: } deba@189: deba@189: /// \brief Destructor deba@189: ~SectionReader() { alpar@209: for (Sections::iterator it = _sections.begin(); alpar@209: it != _sections.end(); ++it) { alpar@209: delete it->second; deba@189: } deba@189: deba@189: if (local_is) { alpar@209: delete _is; deba@189: } deba@189: deba@189: } deba@189: deba@189: private: deba@190: deba@190: friend SectionReader sectionReader(std::istream& is); deba@190: friend SectionReader sectionReader(const std::string& fn); deba@190: friend SectionReader sectionReader(const char* fn); deba@190: alpar@209: SectionReader(SectionReader& other) deba@190: : _is(other._is), local_is(other.local_is) { deba@190: deba@190: other._is = 0; deba@190: other.local_is = false; alpar@209: deba@190: _sections.swap(other._sections); deba@190: } alpar@209: deba@189: SectionReader& operator=(const SectionReader&); deba@189: deba@189: public: deba@189: kpeter@584: /// \name Section Readers deba@189: /// @{ deba@189: deba@189: /// \brief Add a section processor with line oriented reading deba@189: /// deba@189: /// The first parameter is the type descriptor of the section, the deba@189: /// second is a functor, which takes just one \c std::string deba@189: /// parameter. At the reading process, each line of the section deba@189: /// will be given to the functor object. However, the empty lines deba@189: /// and the comment lines are filtered out, and the leading deba@189: /// whitespaces are trimmed from each processed string. deba@189: /// deba@189: /// For example let's see a section, which contain several deba@189: /// integers, which should be inserted into a vector. deba@189: ///\code deba@189: /// @numbers deba@189: /// 12 45 23 deba@189: /// 4 deba@189: /// 23 6 deba@189: ///\endcode deba@189: /// kpeter@192: /// The functor is implemented as a struct: deba@189: ///\code deba@189: /// struct NumberSection { deba@189: /// std::vector& _data; deba@189: /// NumberSection(std::vector& data) : _data(data) {} deba@189: /// void operator()(const std::string& line) { deba@189: /// std::istringstream ls(line); deba@189: /// int value; deba@189: /// while (ls >> value) _data.push_back(value); deba@189: /// } deba@189: /// }; deba@189: /// deba@189: /// // ... deba@189: /// alpar@209: /// reader.sectionLines("numbers", NumberSection(vec)); deba@189: ///\endcode deba@189: template deba@189: SectionReader& sectionLines(const std::string& type, Functor functor) { kpeter@192: LEMON_ASSERT(!type.empty(), "Type is empty."); alpar@209: LEMON_ASSERT(_sections.find(type) == _sections.end(), alpar@209: "Multiple reading of section."); alpar@209: _sections.insert(std::make_pair(type, deba@189: new _reader_bits::LineSection(functor))); deba@189: return *this; deba@189: } deba@189: deba@189: deba@189: /// \brief Add a section processor with stream oriented reading deba@189: /// deba@189: /// The first parameter is the type of the section, the second is kpeter@192: /// a functor, which takes an \c std::istream& and an \c int& deba@189: /// parameter, the latter regard to the line number of stream. The deba@189: /// functor can read the input while the section go on, and the deba@189: /// line number should be modified accordingly. deba@189: template deba@189: SectionReader& sectionStream(const std::string& type, Functor functor) { kpeter@192: LEMON_ASSERT(!type.empty(), "Type is empty."); alpar@209: LEMON_ASSERT(_sections.find(type) == _sections.end(), alpar@209: "Multiple reading of section."); alpar@209: _sections.insert(std::make_pair(type, alpar@209: new _reader_bits::StreamSection(functor))); deba@189: return *this; alpar@209: } alpar@209: deba@189: /// @} deba@189: deba@189: private: deba@189: deba@189: bool readLine() { deba@189: std::string str; deba@189: while(++line_num, std::getline(*_is, str)) { alpar@209: line.clear(); line.str(str); alpar@209: char c; alpar@209: if (line >> std::ws >> c && c != '#') { alpar@209: line.putback(c); alpar@209: return true; alpar@209: } deba@189: } deba@189: return false; deba@189: } deba@189: deba@189: bool readSuccess() { deba@189: return static_cast(*_is); deba@189: } alpar@209: deba@189: void skipSection() { deba@189: char c; deba@189: while (readSuccess() && line >> c && c != '@') { alpar@209: readLine(); deba@189: } deba@427: if (readSuccess()) { deba@427: line.putback(c); deba@427: } deba@189: } deba@189: deba@189: public: deba@189: deba@189: kpeter@584: /// \name Execution of the Reader deba@189: /// @{ deba@189: deba@189: /// \brief Start the batch processing deba@189: /// kpeter@192: /// This function starts the batch processing. deba@189: void run() { alpar@209: deba@189: LEMON_ASSERT(_is != 0, "This reader assigned to an other reader"); alpar@209: deba@189: std::set extra_sections; deba@189: alpar@209: line_num = 0; deba@189: readLine(); deba@189: skipSection(); deba@189: deba@189: while (readSuccess()) { alpar@209: try { alpar@209: char c; alpar@209: std::string section, caption; alpar@209: line >> c; alpar@209: _reader_bits::readToken(line, section); alpar@209: _reader_bits::readToken(line, caption); alpar@209: alpar@209: if (line >> c) kpeter@291: throw FormatError("Extra character at the end of line"); alpar@209: alpar@209: if (extra_sections.find(section) != extra_sections.end()) { alpar@209: std::ostringstream msg; kpeter@291: msg << "Multiple occurence of section: " << section; deba@290: throw FormatError(msg.str()); alpar@209: } alpar@209: Sections::iterator it = _sections.find(section); alpar@209: if (it != _sections.end()) { alpar@209: extra_sections.insert(section); alpar@209: it->second->process(*_is, line_num); alpar@209: } alpar@209: readLine(); alpar@209: skipSection(); deba@290: } catch (FormatError& error) { alpar@209: error.line(line_num); deba@290: error.file(_filename); alpar@209: throw; alpar@209: } deba@189: } deba@189: for (Sections::iterator it = _sections.begin(); alpar@209: it != _sections.end(); ++it) { alpar@209: if (extra_sections.find(it->first) == extra_sections.end()) { alpar@209: std::ostringstream os; alpar@209: os << "Cannot find section: " << it->first; deba@290: throw FormatError(os.str()); alpar@209: } deba@189: } deba@189: } deba@189: deba@189: /// @} alpar@209: deba@189: }; deba@189: deba@598: /// \ingroup lemon_io deba@598: /// deba@598: /// \brief Return a \ref SectionReader class deba@598: /// deba@598: /// This function just returns a \ref SectionReader class. deba@598: /// deba@598: /// Please see SectionReader documentation about the custom section deba@598: /// input. deba@598: /// deba@598: /// \relates SectionReader deba@598: /// \sa sectionReader(const std::string& fn) deba@598: /// \sa sectionReader(const char *fn) deba@598: inline SectionReader sectionReader(std::istream& is) { deba@598: SectionReader tmp(is); deba@598: return tmp; deba@598: } deba@598: kpeter@192: /// \brief Return a \ref SectionReader class alpar@209: /// kpeter@192: /// This function just returns a \ref SectionReader class. deba@189: /// \relates SectionReader deba@598: /// \sa sectionReader(std::istream& is) deba@598: inline SectionReader sectionReader(const std::string& fn) { deba@598: SectionReader tmp(fn); deba@189: return tmp; deba@189: } deba@189: kpeter@192: /// \brief Return a \ref SectionReader class alpar@209: /// kpeter@192: /// This function just returns a \ref SectionReader class. deba@189: /// \relates SectionReader deba@598: /// \sa sectionReader(std::istream& is) deba@189: inline SectionReader sectionReader(const char* fn) { deba@189: SectionReader tmp(fn); deba@189: return tmp; deba@189: } deba@189: deba@173: /// \ingroup lemon_io deba@173: /// alpar@209: /// \brief Reader for the contents of the \ref lgf-format "LGF" file deba@173: /// deba@173: /// This class can be used to read the sections, the map names and ladanyi@236: /// the attributes from a file. Usually, the LEMON programs know deba@173: /// that, which type of graph, which maps and which attributes deba@173: /// should be read from a file, but in general tools (like glemon) alpar@179: /// the contents of an LGF file should be guessed somehow. This class deba@173: /// reads the graph and stores the appropriate information for deba@173: /// reading the graph. deba@173: /// alpar@209: ///\code alpar@209: /// LgfContents contents("graph.lgf"); alpar@179: /// contents.run(); deba@173: /// kpeter@192: /// // Does it contain any node section and arc section? alpar@179: /// if (contents.nodeSectionNum() == 0 || contents.arcSectionNum()) { kpeter@192: /// std::cerr << "Failure, cannot find graph." << std::endl; deba@173: /// return -1; deba@173: /// } alpar@209: /// std::cout << "The name of the default node section: " alpar@179: /// << contents.nodeSection(0) << std::endl; alpar@209: /// std::cout << "The number of the arc maps: " alpar@179: /// << contents.arcMaps(0).size() << std::endl; alpar@209: /// std::cout << "The name of second arc map: " alpar@179: /// << contents.arcMaps(0)[1] << std::endl; deba@173: ///\endcode alpar@209: class LgfContents { deba@173: private: deba@173: deba@173: std::istream* _is; deba@173: bool local_is; deba@173: deba@173: std::vector _node_sections; deba@173: std::vector _edge_sections; deba@173: std::vector _attribute_sections; deba@173: std::vector _extra_sections; deba@173: deba@173: std::vector _arc_sections; deba@173: deba@173: std::vector > _node_maps; deba@173: std::vector > _edge_maps; deba@173: deba@173: std::vector > _attributes; deba@173: deba@173: deba@173: int line_num; deba@173: std::istringstream line; alpar@209: deba@173: public: deba@173: deba@173: /// \brief Constructor deba@173: /// alpar@179: /// Construct an \e LGF contents reader, which reads from the given deba@173: /// input stream. alpar@209: LgfContents(std::istream& is) deba@173: : _is(&is), local_is(false) {} deba@173: deba@173: /// \brief Constructor deba@173: /// alpar@179: /// Construct an \e LGF contents reader, which reads from the given deba@173: /// file. alpar@209: LgfContents(const std::string& fn) deba@290: : _is(new std::ifstream(fn.c_str())), local_is(true) { deba@295: if (!(*_is)) { deba@295: delete _is; deba@295: throw IoError("Cannot open file", fn); deba@295: } deba@290: } deba@173: deba@173: /// \brief Constructor deba@173: /// alpar@179: /// Construct an \e LGF contents reader, which reads from the given deba@173: /// file. alpar@179: LgfContents(const char* fn) deba@290: : _is(new std::ifstream(fn)), local_is(true) { deba@295: if (!(*_is)) { deba@295: delete _is; deba@295: throw IoError("Cannot open file", fn); deba@295: } deba@290: } alpar@209: deba@173: /// \brief Destructor alpar@179: ~LgfContents() { deba@173: if (local_is) delete _is; deba@173: } deba@173: deba@190: private: alpar@209: deba@190: LgfContents(const LgfContents&); deba@190: LgfContents& operator=(const LgfContents&); deba@190: deba@190: public: deba@190: deba@173: kpeter@584: /// \name Node Sections deba@173: /// @{ deba@173: deba@173: /// \brief Gives back the number of node sections in the file. deba@173: /// deba@173: /// Gives back the number of node sections in the file. deba@173: int nodeSectionNum() const { deba@173: return _node_sections.size(); deba@173: } deba@173: alpar@209: /// \brief Returns the node section name at the given position. deba@173: /// alpar@209: /// Returns the node section name at the given position. deba@173: const std::string& nodeSection(int i) const { deba@173: return _node_sections[i]; deba@173: } deba@173: deba@173: /// \brief Gives back the node maps for the given section. deba@173: /// deba@173: /// Gives back the node maps for the given section. alpar@182: const std::vector& nodeMapNames(int i) const { deba@173: return _node_maps[i]; deba@173: } deba@173: deba@173: /// @} deba@173: kpeter@584: /// \name Arc/Edge Sections deba@173: /// @{ deba@173: alpar@181: /// \brief Gives back the number of arc/edge sections in the file. deba@173: /// alpar@181: /// Gives back the number of arc/edge sections in the file. alpar@181: /// \note It is synonym of \c edgeSectionNum(). deba@173: int arcSectionNum() const { deba@173: return _edge_sections.size(); deba@173: } deba@173: alpar@209: /// \brief Returns the arc/edge section name at the given position. deba@173: /// alpar@209: /// Returns the arc/edge section name at the given position. alpar@181: /// \note It is synonym of \c edgeSection(). deba@173: const std::string& arcSection(int i) const { deba@173: return _edge_sections[i]; deba@173: } deba@173: alpar@181: /// \brief Gives back the arc/edge maps for the given section. deba@173: /// alpar@181: /// Gives back the arc/edge maps for the given section. alpar@182: /// \note It is synonym of \c edgeMapNames(). alpar@182: const std::vector& arcMapNames(int i) const { deba@173: return _edge_maps[i]; deba@173: } deba@173: deba@173: /// @} deba@173: alpar@181: /// \name Synonyms deba@173: /// @{ deba@173: alpar@181: /// \brief Gives back the number of arc/edge sections in the file. deba@173: /// alpar@181: /// Gives back the number of arc/edge sections in the file. alpar@181: /// \note It is synonym of \c arcSectionNum(). deba@173: int edgeSectionNum() const { deba@173: return _edge_sections.size(); deba@173: } deba@173: alpar@209: /// \brief Returns the section name at the given position. deba@173: /// alpar@209: /// Returns the section name at the given position. alpar@181: /// \note It is synonym of \c arcSection(). deba@173: const std::string& edgeSection(int i) const { deba@173: return _edge_sections[i]; deba@173: } deba@173: deba@173: /// \brief Gives back the edge maps for the given section. deba@173: /// deba@173: /// Gives back the edge maps for the given section. alpar@182: /// \note It is synonym of \c arcMapNames(). alpar@182: const std::vector& edgeMapNames(int i) const { deba@173: return _edge_maps[i]; deba@173: } deba@173: deba@173: /// @} deba@173: kpeter@584: /// \name Attribute Sections deba@173: /// @{ deba@173: deba@173: /// \brief Gives back the number of attribute sections in the file. deba@173: /// deba@173: /// Gives back the number of attribute sections in the file. deba@173: int attributeSectionNum() const { deba@173: return _attribute_sections.size(); deba@173: } deba@173: alpar@209: /// \brief Returns the attribute section name at the given position. deba@173: /// alpar@209: /// Returns the attribute section name at the given position. alpar@182: const std::string& attributeSectionNames(int i) const { deba@173: return _attribute_sections[i]; deba@173: } deba@173: deba@173: /// \brief Gives back the attributes for the given section. deba@173: /// deba@173: /// Gives back the attributes for the given section. deba@173: const std::vector& attributes(int i) const { deba@173: return _attributes[i]; deba@173: } deba@173: deba@173: /// @} deba@173: kpeter@584: /// \name Extra Sections deba@173: /// @{ deba@173: deba@173: /// \brief Gives back the number of extra sections in the file. deba@173: /// deba@173: /// Gives back the number of extra sections in the file. deba@173: int extraSectionNum() const { deba@173: return _extra_sections.size(); deba@173: } deba@173: alpar@209: /// \brief Returns the extra section type at the given position. deba@173: /// alpar@209: /// Returns the section type at the given position. deba@173: const std::string& extraSection(int i) const { deba@173: return _extra_sections[i]; deba@173: } deba@173: deba@173: /// @} deba@173: deba@173: private: deba@173: deba@173: bool readLine() { deba@173: std::string str; deba@173: while(++line_num, std::getline(*_is, str)) { alpar@209: line.clear(); line.str(str); alpar@209: char c; alpar@209: if (line >> std::ws >> c && c != '#') { alpar@209: line.putback(c); alpar@209: return true; alpar@209: } deba@173: } deba@173: return false; deba@173: } deba@173: deba@173: bool readSuccess() { deba@173: return static_cast(*_is); deba@173: } deba@173: deba@173: void skipSection() { deba@173: char c; deba@173: while (readSuccess() && line >> c && c != '@') { alpar@209: readLine(); deba@173: } deba@427: if (readSuccess()) { deba@427: line.putback(c); deba@427: } deba@173: } deba@173: deba@173: void readMaps(std::vector& maps) { deba@186: char c; deba@186: if (!readLine() || !(line >> c) || c == '@') { alpar@209: if (readSuccess() && line) line.putback(c); alpar@209: return; deba@186: } deba@186: line.putback(c); deba@173: std::string map; deba@173: while (_reader_bits::readToken(line, map)) { alpar@209: maps.push_back(map); deba@173: } deba@173: } deba@173: deba@173: void readAttributes(std::vector& attrs) { deba@173: readLine(); deba@173: char c; deba@173: while (readSuccess() && line >> c && c != '@') { alpar@209: line.putback(c); alpar@209: std::string attr; alpar@209: _reader_bits::readToken(line, attr); alpar@209: attrs.push_back(attr); alpar@209: readLine(); deba@173: } deba@173: line.putback(c); deba@173: } deba@173: deba@173: public: deba@173: kpeter@584: /// \name Execution of the Contents Reader deba@173: /// @{ deba@173: kpeter@192: /// \brief Starts the reading deba@173: /// kpeter@192: /// This function starts the reading. deba@173: void run() { deba@173: deba@173: readLine(); deba@173: skipSection(); deba@173: deba@173: while (readSuccess()) { deba@173: alpar@209: char c; alpar@209: line >> c; alpar@209: alpar@209: std::string section, caption; alpar@209: _reader_bits::readToken(line, section); alpar@209: _reader_bits::readToken(line, caption); alpar@209: alpar@209: if (section == "nodes") { alpar@209: _node_sections.push_back(caption); alpar@209: _node_maps.push_back(std::vector()); alpar@209: readMaps(_node_maps.back()); alpar@209: readLine(); skipSection(); alpar@209: } else if (section == "arcs" || section == "edges") { alpar@209: _edge_sections.push_back(caption); alpar@209: _arc_sections.push_back(section == "arcs"); alpar@209: _edge_maps.push_back(std::vector()); alpar@209: readMaps(_edge_maps.back()); alpar@209: readLine(); skipSection(); alpar@209: } else if (section == "attributes") { alpar@209: _attribute_sections.push_back(caption); alpar@209: _attributes.push_back(std::vector()); alpar@209: readAttributes(_attributes.back()); alpar@209: } else { alpar@209: _extra_sections.push_back(section); alpar@209: readLine(); skipSection(); alpar@209: } deba@173: } deba@173: } deba@173: deba@173: /// @} alpar@209: deba@173: }; deba@127: } deba@127: deba@127: #endif