deba@1408: /* -*- C++ -*- deba@1408: * src/lemon/lemon_reader.h - Part of LEMON, a generic C++ optimization library deba@1408: * deba@1408: * Copyright (C) 2005 Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport deba@1408: * (Egervary Research Group on Combinatorial Optimization, EGRES). deba@1408: * deba@1408: * Permission to use, modify and distribute this software is granted deba@1408: * provided that this copyright notice appears in all copies. For deba@1408: * precise terms see the accompanying LICENSE file. deba@1408: * deba@1408: * This software is provided "AS IS" with no warranty of any kind, deba@1408: * express or implied, and with no claim as to its suitability for any deba@1408: * purpose. deba@1408: * deba@1408: */ deba@1408: deba@1408: ///\ingroup io_group deba@1408: ///\file deba@1408: ///\brief Lemon Format reader. deba@1408: deba@1408: #ifndef LEMON_LEMON_READER_H deba@1408: #define LEMON_LEMON_READER_H deba@1408: deba@1408: #include deba@1408: #include deba@1408: #include deba@1408: #include deba@1408: #include deba@1408: #include deba@1408: #include deba@1408: deba@1408: #include deba@1408: #include "item_reader.h" deba@1408: deba@1408: deba@1408: namespace lemon { deba@1408: deba@1408: /// \addtogroup io_group deba@1408: /// @{ deba@1408: deba@1408: /// \brief Lemon Format reader class. deba@1408: /// deba@1408: class LemonReader { deba@1408: private: deba@1408: deba@1408: class FilterStreamBuf : public std::streambuf { deba@1408: public: deba@1408: deba@1408: typedef std::streambuf Parent; deba@1408: typedef Parent::char_type char_type; deba@1408: FilterStreamBuf(std::istream& is, int& num) deba@1408: : _is(is), _base(0), _eptr(0), deba@1408: _num(num), skip_state(after_endl) {} deba@1408: deba@1408: protected: deba@1408: deba@1408: enum skip_state_type { deba@1408: no_skip, deba@1408: after_comment, deba@1408: after_endl, deba@1408: empty_line deba@1408: }; deba@1408: deba@1408: char_type small_buf[1]; deba@1408: deba@1408: deba@1408: std::istream& _is; deba@1408: deba@1408: char_type* _base; deba@1408: char_type* _eptr; deba@1408: deba@1408: int& _num; deba@1408: deba@1408: skip_state_type skip_state; deba@1408: deba@1408: deba@1408: char_type* base() { return _base; } deba@1408: deba@1408: char_type* eptr() { return _eptr; } deba@1408: deba@1408: int blen() { return _eptr - _base; } deba@1408: deba@1408: void setb(char_type* buf, int len) { deba@1408: _base = buf; deba@1408: _eptr = buf + len; deba@1408: } deba@1408: deba@1408: virtual std::streambuf* setbuf(char *buf, int len) { deba@1408: if (base()) return 0; deba@1408: if (buf != 0 && len >= (int)sizeof(small_buf)) { deba@1408: setb(buf, len); deba@1408: } else { deba@1408: setb(small_buf, sizeof(small_buf)); deba@1408: } deba@1408: setg(0, 0, 0); deba@1408: return this; deba@1408: } deba@1408: deba@1408: bool put_char(char c) { deba@1408: switch (skip_state) { deba@1408: case no_skip: deba@1408: switch (c) { deba@1408: case '\n': deba@1408: skip_state = after_endl; deba@1408: return true; deba@1408: case '#': deba@1408: skip_state = after_comment; deba@1408: return false; deba@1408: default: deba@1408: return true; deba@1408: } deba@1408: case after_comment: deba@1408: switch (c) { deba@1408: case '\n': deba@1408: skip_state = after_endl; deba@1408: return true; deba@1408: default: deba@1408: return false; deba@1408: } deba@1408: case after_endl: deba@1408: switch (c) { deba@1408: case '@': deba@1408: return false; deba@1408: case '\n': deba@1408: return false; deba@1408: case '#': deba@1408: skip_state = empty_line; deba@1408: return false; deba@1408: default: deba@1408: if (!isspace(c)) { deba@1408: skip_state = no_skip; deba@1408: return true; deba@1408: } else { deba@1408: return false; deba@1408: } deba@1408: } deba@1408: break; deba@1408: case empty_line: deba@1408: switch (c) { deba@1408: case '\n': deba@1408: skip_state = after_endl; deba@1408: return false; deba@1408: default: deba@1408: return false; deba@1408: } deba@1408: } deba@1408: return false; deba@1408: } deba@1408: deba@1408: virtual int underflow() { deba@1408: char c; deba@1408: if (_is.read(&c, 1)) { deba@1408: _is.putback(c); deba@1408: if (c == '@') { deba@1408: return EOF; deba@1408: } deba@1408: } else { deba@1408: return EOF; deba@1408: } deba@1408: char_type *ptr; deba@1408: for (ptr = base(); ptr != eptr(); ++ptr) { deba@1408: if (_is.read(&c, 1)) { deba@1408: if (c == '\n') ++_num; deba@1408: if (put_char(c)) { deba@1408: *ptr = c; deba@1408: } else { deba@1408: if (skip_state == after_endl && c == '@') { deba@1408: _is.putback('@'); deba@1408: break; deba@1408: } deba@1408: --ptr; deba@1408: } deba@1408: } else { deba@1408: break; deba@1408: } deba@1408: } deba@1408: setg(base(), base(), ptr); deba@1408: return *base(); deba@1408: } deba@1408: deba@1408: virtual int sync() { deba@1408: return EOF; deba@1408: } deba@1408: }; deba@1408: deba@1408: public: deba@1408: deba@1408: class SectionReader { deba@1408: public: deba@1408: /// \e deba@1408: virtual bool header(const std::string& line) = 0; deba@1408: /// \e deba@1408: virtual void read(std::istream& is) = 0; deba@1408: }; deba@1408: deba@1408: /// \e deba@1408: LemonReader(std::istream& _is) deba@1408: : is(&_is), own_is(false) {} deba@1408: deba@1408: LemonReader(const std::string& filename) deba@1408: : is(0), own_is(true) { deba@1408: is = new std::ifstream(filename.c_str()); deba@1408: } deba@1408: deba@1408: deba@1408: ~LemonReader() { deba@1408: if (own_is) { deba@1408: delete is; deba@1408: } deba@1408: } deba@1408: deba@1408: private: deba@1408: LemonReader(const LemonReader&); deba@1408: void operator=(const LemonReader&); deba@1408: deba@1408: public: deba@1408: deba@1408: /// \e deba@1408: void attach(SectionReader& reader) { deba@1408: readers.push_back(&reader); deba@1408: } deba@1408: deba@1408: /// \e deba@1408: void detach(SectionReader& reader) { deba@1408: std::vector::iterator it = deba@1408: std::find(readers.begin(), readers.end(), &reader); deba@1408: if (it != readers.end()) { deba@1408: readers.erase(it); deba@1408: } deba@1408: } deba@1408: deba@1408: /// \e deba@1408: void run() { deba@1408: int line_num = 0; deba@1408: std::string line; deba@1408: try { deba@1408: while ((++line_num, getline(*is, line)) && line.find("@end") != 0) { deba@1408: SectionReaders::iterator it; deba@1408: for (it = readers.begin(); it != readers.end(); ++it) { deba@1408: if ((*it)->header(line)) { deba@1408: char buf[2048]; deba@1408: FilterStreamBuf buffer(*is, line_num); deba@1408: buffer.pubsetbuf(buf, sizeof(buf)); deba@1408: std::istream is(&buffer); deba@1408: (*it)->read(is); deba@1408: break; deba@1408: } deba@1408: } deba@1408: } deba@1408: } catch (DataFormatError& error) { deba@1408: error.line(line_num); deba@1408: throw error; deba@1408: } deba@1408: } deba@1408: deba@1408: deba@1408: private: deba@1408: deba@1408: std::istream* is; deba@1408: bool own_is; deba@1408: deba@1408: typedef std::vector SectionReaders; deba@1408: SectionReaders readers; deba@1408: deba@1408: }; deba@1408: deba@1408: deba@1408: /// \e deba@1408: class CommonSectionReaderBase : public LemonReader::SectionReader { deba@1408: protected: deba@1408: template deba@1408: class ReaderBase; deba@1408: deba@1408: template deba@1408: class InverterBase : public ReaderBase<_Item> { deba@1408: public: deba@1408: typedef _Item Item; deba@1408: virtual void read(std::istream&, const Item&) = 0; deba@1408: virtual Item read(std::istream&) const = 0; deba@1408: deba@1408: virtual InverterBase<_Item>* getInverter() { deba@1408: return this; deba@1408: } deba@1408: deba@1408: deba@1408: }; deba@1408: deba@1408: template deba@1408: class MapReaderInverter : public InverterBase<_Item> { deba@1408: public: deba@1408: typedef _Item Item; deba@1408: typedef _Reader Reader; deba@1408: typedef typename Reader::Value Value; deba@1408: typedef _Map Map; deba@1408: typedef std::map Inverse; deba@1408: deba@1408: Map& map; deba@1408: Reader reader; deba@1408: Inverse inverse; deba@1408: deba@1408: MapReaderInverter(Map& _map, const Reader& _reader) deba@1408: : map(_map), reader(_reader) {} deba@1408: deba@1408: virtual ~MapReaderInverter() {} deba@1408: deba@1408: virtual void read(std::istream& is, const Item& item) { deba@1408: Value value; deba@1408: reader.read(is, value); deba@1408: map.set(item, value); deba@1408: typename Inverse::iterator it = inverse.find(value); deba@1408: if (it == inverse.end()) { deba@1408: inverse.insert(std::make_pair(value, item)); deba@1408: } else { deba@1408: throw DataFormatError("Multiple ID occurence"); deba@1408: } deba@1408: } deba@1408: deba@1408: virtual Item read(std::istream& is) const { deba@1408: Value value; deba@1408: reader.read(is, value); deba@1408: typename Inverse::const_iterator it = inverse.find(value); deba@1408: if (it != inverse.end()) { deba@1408: return it->second; deba@1408: } else { deba@1408: throw DataFormatError("Invalid ID error"); deba@1408: } deba@1408: } deba@1408: deba@1408: }; deba@1408: deba@1408: template deba@1408: class SkipReaderInverter : public InverterBase<_Item> { deba@1408: public: deba@1408: typedef _Item Item; deba@1408: typedef _Reader Reader; deba@1408: typedef typename Reader::Value Value; deba@1408: typedef std::map Inverse; deba@1408: deba@1408: Reader reader; deba@1408: deba@1408: SkipReaderInverter(const Reader& _reader) deba@1408: : reader(_reader) {} deba@1408: deba@1408: virtual ~SkipReaderInverter() {} deba@1408: deba@1408: virtual void read(std::istream& is, const Item& item) { deba@1408: Value value; deba@1408: reader.read(is, value); deba@1408: typename Inverse::iterator it = inverse.find(value); deba@1408: if (it == inverse.end()) { deba@1408: inverse.insert(std::make_pair(value, item)); deba@1408: } else { deba@1408: throw DataFormatError("Multiple ID occurence error"); deba@1408: } deba@1408: } deba@1408: deba@1408: virtual Item read(std::istream& is) const { deba@1408: Value value; deba@1408: reader.read(is, value); deba@1408: typename Inverse::const_iterator it = inverse.find(value); deba@1408: if (it != inverse.end()) { deba@1408: return it->second; deba@1408: } else { deba@1408: throw DataFormatError("Invalid ID error"); deba@1408: } deba@1408: } deba@1408: deba@1408: private: deba@1408: Inverse inverse; deba@1408: }; deba@1408: deba@1408: // Readers deba@1408: deba@1408: template deba@1408: class ReaderBase { deba@1408: public: deba@1408: typedef _Item Item; deba@1408: deba@1408: virtual ~ReaderBase() {} deba@1408: deba@1408: virtual void read(std::istream& is, const Item& item) = 0; deba@1408: virtual InverterBase<_Item>* getInverter() = 0; deba@1408: }; deba@1408: deba@1408: template deba@1408: class MapReader : public ReaderBase<_Item> { deba@1408: public: deba@1408: typedef _Map Map; deba@1408: typedef _Reader Reader; deba@1408: typedef typename Reader::Value Value; deba@1408: typedef _Item Item; deba@1408: deba@1408: Map& map; deba@1408: Reader reader; deba@1408: deba@1408: MapReader(Map& _map, const Reader& _reader) deba@1408: : map(_map), reader(_reader) {} deba@1408: deba@1408: virtual ~MapReader() {} deba@1408: deba@1408: virtual void read(std::istream& is, const Item& item) { deba@1408: Value value; deba@1408: reader.read(is, value); deba@1408: map.set(item, value); deba@1408: } deba@1408: deba@1408: virtual InverterBase<_Item>* getInverter() { deba@1408: return new MapReaderInverter(map, reader); deba@1408: } deba@1408: }; deba@1408: deba@1408: deba@1408: template deba@1408: class SkipReader : public ReaderBase<_Item> { deba@1408: public: deba@1408: typedef _Reader Reader; deba@1408: typedef typename Reader::Value Value; deba@1408: typedef _Item Item; deba@1408: deba@1408: Reader reader; deba@1408: SkipReader(const Reader& _reader) : reader(_reader) {} deba@1408: deba@1408: virtual ~SkipReader() {} deba@1408: deba@1408: virtual void read(std::istream& is, const Item&) { deba@1408: Value value; deba@1408: reader.read(is, value); deba@1408: } deba@1408: deba@1408: virtual InverterBase* getInverter() { deba@1408: return new SkipReaderInverter(reader); deba@1408: } deba@1408: }; deba@1408: deba@1408: template deba@1408: class ResolverReaderBase { deba@1408: public: deba@1408: typedef _Item Item; deba@1408: virtual Item resolve(std::istream& is) const = 0; deba@1408: }; deba@1408: deba@1408: template deba@1408: class ResolverReader : public ResolverReaderBase<_Item> { deba@1408: public: deba@1408: typedef _Item Item; deba@1408: typedef _Resolver Resolver; deba@1408: deba@1408: const Resolver& resolver; deba@1408: deba@1408: ResolverReader(const Resolver& _resolver) deba@1408: : resolver(_resolver) {} deba@1408: deba@1408: virtual Item resolve(std::istream& is) const { deba@1408: return resolver.resolve(is); deba@1408: } deba@1408: }; deba@1408: deba@1408: class ValueReaderBase { deba@1408: public: deba@1408: virtual void read(std::istream&) {}; deba@1408: }; deba@1408: deba@1408: template deba@1408: class ValueReader : public ValueReaderBase { deba@1408: public: deba@1408: typedef _Value Value; deba@1408: typedef _Reader Reader; deba@1408: deba@1408: ValueReader(Value& _value, const Reader& _reader) deba@1408: : value(_value), reader(_reader) {} deba@1408: deba@1408: virtual void read(std::istream& is) { deba@1408: reader.read(is, value); deba@1408: } deba@1408: private: deba@1408: Value& value; deba@1408: Reader reader; deba@1408: }; deba@1408: deba@1408: }; deba@1408: deba@1408: deba@1408: template deba@1408: class NodeSetReader : public CommonSectionReaderBase { deba@1408: typedef CommonSectionReaderBase Parent; deba@1408: public: deba@1408: deba@1408: typedef _Graph Graph; deba@1408: typedef _Traits Traits; deba@1408: typedef typename Graph::Node Item; deba@1408: typedef typename Traits::Skipper DefaultSkipper; deba@1408: deba@1408: NodeSetReader(LemonReader& _reader, Graph& _graph, deba@1408: const std::string& _id = std::string(), deba@1408: const DefaultSkipper& _defreader = DefaultSkipper()) deba@1408: : graph(_graph), id(_id), skipper(_defreader) { deba@1408: _reader.attach(*this); deba@1408: } deba@1408: deba@1408: virtual ~NodeSetReader() { deba@1408: for (typename MapReaders::iterator it = readers.begin(); deba@1408: it != readers.end(); ++it) { deba@1408: delete it->second; deba@1408: } deba@1408: } deba@1408: deba@1408: private: deba@1408: NodeSetReader(const NodeSetReader&); deba@1408: void operator=(const NodeSetReader&); deba@1408: deba@1408: public: deba@1408: deba@1408: /// \brief Add a new node map reader command for the reader. deba@1408: /// deba@1408: /// Add a new node map reader command for the reader. deba@1408: template deba@1408: NodeSetReader& readMap(std::string name, Map& map) { deba@1408: return readMap, Map>(name, map); deba@1408: } deba@1408: deba@1408: /// \brief Add a new node map reader command for the reader. deba@1408: /// deba@1408: /// Add a new node map reader command for the reader. deba@1408: template deba@1408: NodeSetReader& readMap(std::string name, Map& map, deba@1408: const Reader& reader = Reader()) { deba@1408: if (readers.find(name) != readers.end()) { deba@1408: ErrorMessage msg; deba@1408: msg << "Multiple read rule for node map: " << name; deba@1408: throw IOParameterError(msg.message()); deba@1408: } deba@1408: readers.insert( deba@1408: make_pair(name, new MapReader(map, reader))); deba@1408: return *this; deba@1408: } deba@1408: deba@1408: /// \brief Add a new node map skipper command for the reader. deba@1408: /// deba@1408: /// Add a new node map skipper command for the reader. deba@1408: template deba@1408: NodeSetReader& skipMap(std::string name, deba@1408: const Reader& reader = Reader()) { deba@1408: if (readers.find(name) != readers.end()) { deba@1408: ErrorMessage msg; deba@1408: msg << "Multiple read rule for node map: " << name; deba@1408: throw IOParameterError(msg.message()); deba@1408: } deba@1408: readers.insert(make_pair(name, new SkipReader(reader))); deba@1408: return *this; deba@1408: } deba@1408: deba@1408: /// \e deba@1408: virtual bool header(const std::string& line) { deba@1408: std::istringstream ls(line); deba@1408: std::string command; deba@1408: std::string name; deba@1408: ls >> command >> name; deba@1408: return command == "@nodeset" && name == id; deba@1408: } deba@1408: deba@1408: /// \e deba@1408: virtual void read(std::istream& is) { deba@1408: std::vector* > index; deba@1408: std::string line; deba@1408: deba@1408: getline(is, line); deba@1408: std::istringstream ls(line); deba@1408: while (ls >> id) { deba@1408: typename MapReaders::iterator it = readers.find(id); deba@1408: if (it != readers.end()) { deba@1408: index.push_back(it->second); deba@1408: } else { deba@1408: index.push_back(&skipper); deba@1408: } deba@1408: if (id == "id" && inverter.get() == 0) { deba@1408: inverter.reset(index.back()->getInverter()); deba@1408: index.back() = inverter.get(); deba@1408: } deba@1408: } deba@1408: while (getline(is, line)) { deba@1408: typename Graph::Node node = graph.addNode(); deba@1408: std::istringstream ls(line); deba@1408: for (int i = 0; i < (int)index.size(); ++i) { deba@1408: index[i]->read(ls, node); deba@1408: } deba@1408: } deba@1408: } deba@1408: deba@1408: bool isResolver() const { deba@1408: return inverter.get() != 0; deba@1408: } deba@1408: deba@1408: typename Graph::Node resolve(std::istream& is) const { deba@1408: return inverter->read(is); deba@1408: } deba@1408: deba@1408: private: deba@1408: deba@1408: typedef std::map*> MapReaders; deba@1408: MapReaders readers; deba@1408: deba@1408: Graph& graph; deba@1408: std::string id; deba@1408: SkipReader skipper; deba@1408: deba@1408: std::auto_ptr > inverter; deba@1408: }; deba@1408: deba@1408: deba@1408: deba@1408: /// \e deba@1408: template deba@1408: class EdgeSetReader : public CommonSectionReaderBase { deba@1408: typedef CommonSectionReaderBase Parent; deba@1408: public: deba@1408: deba@1408: typedef _Graph Graph; deba@1408: typedef _Traits Traits; deba@1408: typedef typename Graph::Edge Item; deba@1408: typedef typename Traits::Skipper DefaultSkipper; deba@1408: deba@1408: template deba@1408: EdgeSetReader(LemonReader& _reader, Graph& _graph, deba@1408: const Resolver& _nodeResolver, deba@1408: const std::string& _id = std::string(), deba@1408: const DefaultSkipper& _defreader = DefaultSkipper()) deba@1408: : graph(_graph), id(_id), skipper(_defreader), deba@1408: nodeResolver(new ResolverReader deba@1408: (_nodeResolver)) { deba@1408: _reader.attach(*this); deba@1408: } deba@1408: deba@1408: virtual ~EdgeSetReader() { deba@1408: for (typename MapReaders::iterator it = readers.begin(); deba@1408: it != readers.end(); ++it) { deba@1408: delete it->second; deba@1408: } deba@1408: } deba@1408: deba@1408: private: deba@1408: EdgeSetReader(const EdgeSetReader&); deba@1408: void operator=(const EdgeSetReader&); deba@1408: deba@1408: public: deba@1408: deba@1408: /// \brief Add a new node map reader command for the reader. deba@1408: /// deba@1408: /// Add a new node map reader command for the reader. deba@1408: template deba@1408: EdgeSetReader& readMap(std::string name, Map& map) { deba@1408: return readMap, Map>(name, map); deba@1408: } deba@1408: deba@1408: /// \brief Add a new node map reader command for the reader. deba@1408: /// deba@1408: /// Add a new node map reader command for the reader. deba@1408: template deba@1408: EdgeSetReader& readMap(std::string name, Map& map, deba@1408: const Reader& reader = Reader()) { deba@1408: if (readers.find(name) != readers.end()) { deba@1408: ErrorMessage msg; deba@1408: msg << "Multiple read rule for edge map: " << name; deba@1408: throw IOParameterError(msg.message()); deba@1408: } deba@1408: readers.insert( deba@1408: make_pair(name, new MapReader(map, reader))); deba@1408: return *this; deba@1408: } deba@1408: deba@1408: /// \brief Add a new node map skipper command for the reader. deba@1408: /// deba@1408: /// Add a new node map skipper command for the reader. deba@1408: template deba@1408: EdgeSetReader& skipMap(std::string name, deba@1408: const Reader& reader = Reader()) { deba@1408: if (readers.find(name) != readers.end()) { deba@1408: ErrorMessage msg; deba@1408: msg << "Multiple read rule for node map: " << name; deba@1408: throw IOParameterError(msg.message()); deba@1408: } deba@1408: readers.insert(make_pair(name, new SkipReader(reader))); deba@1408: return *this; deba@1408: } deba@1408: deba@1408: /// \e deba@1408: virtual bool header(const std::string& line) { deba@1408: std::istringstream ls(line); deba@1408: std::string command; deba@1408: std::string name; deba@1408: ls >> command >> name; deba@1408: return command == "@edgeset" && name == id; deba@1408: } deba@1408: deba@1408: /// \e deba@1408: virtual void read(std::istream& is) { deba@1408: std::vector* > index; deba@1408: std::string line; deba@1408: deba@1408: getline(is, line); deba@1408: std::istringstream ls(line); deba@1408: while (ls >> id) { deba@1408: typename MapReaders::iterator it = readers.find(id); deba@1408: if (it != readers.end()) { deba@1408: index.push_back(it->second); deba@1408: } else { deba@1408: index.push_back(&skipper); deba@1408: } deba@1408: if (id == "id" && inverter.get() == 0) { deba@1408: inverter.reset(index.back()->getInverter()); deba@1408: index.back() = inverter.get(); deba@1408: } deba@1408: } deba@1408: while (getline(is, line)) { deba@1408: std::istringstream ls(line); deba@1408: typename Graph::Node from = nodeResolver->resolve(ls); deba@1408: typename Graph::Node to = nodeResolver->resolve(ls); deba@1408: typename Graph::Edge edge = graph.addEdge(from, to); deba@1408: for (int i = 0; i < (int)index.size(); ++i) { deba@1408: index[i]->read(ls, edge); deba@1408: } deba@1408: } deba@1408: } deba@1408: deba@1408: bool isResolver() const { deba@1408: return inverter.get() != 0; deba@1408: } deba@1408: deba@1408: typename Graph::Edge resolve(std::istream& is) { deba@1408: return inverter->read(is); deba@1408: } deba@1408: deba@1408: private: deba@1408: deba@1408: typedef std::map*> MapReaders; deba@1408: MapReaders readers; deba@1408: deba@1408: Graph& graph; deba@1408: std::string id; deba@1408: SkipReader skipper; deba@1408: deba@1408: std::auto_ptr > inverter; deba@1408: std::auto_ptr > nodeResolver; deba@1408: }; deba@1408: deba@1408: deba@1408: /// \e deba@1408: template deba@1408: class AttributeReader : public CommonSectionReaderBase { deba@1408: typedef CommonSectionReaderBase Parent; deba@1408: typedef _Traits Traits; deba@1408: public: deba@1408: /// \e deba@1408: AttributeReader(LemonReader& _reader, deba@1408: const std::string& _id = std::string()) : id(_id) { deba@1408: _reader.attach(*this); deba@1408: } deba@1408: deba@1408: /// \e deba@1408: virtual ~AttributeReader() { deba@1408: for (typename Readers::iterator it = readers.begin(); deba@1408: it != readers.end(); ++it) { deba@1408: delete it->second; deba@1408: } deba@1408: } deba@1408: deba@1408: private: deba@1408: AttributeReader(const AttributeReader&); deba@1408: void operator=(AttributeReader&); deba@1408: deba@1408: public: deba@1408: /// \e deba@1408: template deba@1408: AttributeReader& readAttribute(const std::string& id, Value& value) { deba@1408: return readAttribute > deba@1408: (id, value); deba@1408: } deba@1408: deba@1408: /// \e deba@1408: template deba@1408: AttributeReader& readAttribute(const std::string& name, Value& value, deba@1408: const Reader& reader = Reader()) { deba@1408: if (readers.find(name) != readers.end()) { deba@1408: ErrorMessage msg; deba@1408: msg << "Multiple read rule for attribute: " << name; deba@1408: throw IOParameterError(msg.message()); deba@1408: } deba@1408: readers.insert(make_pair(name, new ValueReader deba@1408: (value, reader))); deba@1408: return *this; deba@1408: } deba@1408: deba@1408: /// \e deba@1408: bool header(const std::string& line) { deba@1408: std::istringstream ls(line); deba@1408: std::string command; deba@1408: std::string name; deba@1408: ls >> command >> name; deba@1408: return command == "@attributes" && name == id; deba@1408: } deba@1408: deba@1408: /// \e deba@1408: void read(std::istream& is) { deba@1408: std::string line; deba@1408: while (getline(is, line)) { deba@1408: std::istringstream ls(line); deba@1408: std::string id; deba@1408: ls >> id; deba@1408: typename Readers::iterator it = readers.find(id); deba@1408: if (it != readers.end()) { deba@1408: it->second->read(ls); deba@1408: } deba@1408: } deba@1408: } deba@1408: deba@1408: private: deba@1408: std::string id; deba@1408: deba@1408: typedef std::map Readers; deba@1408: Readers readers; deba@1408: deba@1408: }; deba@1408: deba@1408: template deba@1408: class NodeReader : public CommonSectionReaderBase { deba@1408: typedef CommonSectionReaderBase Parent; deba@1408: typedef _Graph Graph; deba@1408: typedef typename Graph::Node Item; deba@1408: public: deba@1408: deba@1408: template deba@1408: NodeReader(LemonReader& _reader, const Resolver& _resolver, deba@1408: const std::string& _id = std::string()) deba@1408: : id(_id), resolver(new ResolverReader deba@1408: (_resolver)) { deba@1408: _reader.attach(*this); deba@1408: } deba@1408: deba@1408: virtual ~NodeReader() {} deba@1408: deba@1408: private: deba@1408: NodeReader(const NodeReader&); deba@1408: void operator=(const NodeReader&); deba@1408: deba@1408: public: deba@1408: deba@1408: void readNode(const std::string& name, Item& item) { deba@1408: if (readers.find(name) != readers.end()) { deba@1408: ErrorMessage msg; deba@1408: msg << "Multiple read rule for node: " << name; deba@1408: throw IOParameterError(msg.message()); deba@1408: } deba@1408: readers.insert(make_pair(name, &item)); deba@1408: } deba@1408: deba@1408: virtual bool header(const std::string& line) { deba@1408: std::istringstream ls(line); deba@1408: std::string command; deba@1408: std::string name; deba@1408: ls >> command >> name; deba@1408: return command == "@nodes" && name == id; deba@1408: } deba@1408: deba@1408: virtual void read(std::istream& is) { deba@1408: std::string line; deba@1408: while (getline(is, line)) { deba@1408: std::istringstream ls(line); deba@1408: std::string id; deba@1408: ls >> id; deba@1408: typename ItemReaders::iterator it = readers.find(id); deba@1408: if (it != readers.end()) { deba@1408: *(it->second) = resolver->resolve(ls); deba@1408: } deba@1408: } deba@1408: } deba@1408: deba@1408: private: deba@1408: deba@1408: std::string id; deba@1408: deba@1408: typedef std::map ItemReaders; deba@1408: ItemReaders readers; deba@1408: std::auto_ptr > resolver; deba@1408: }; deba@1408: deba@1408: template deba@1408: class EdgeReader : public CommonSectionReaderBase { deba@1408: typedef CommonSectionReaderBase Parent; deba@1408: typedef _Graph Graph; deba@1408: typedef typename Graph::Edge Item; deba@1408: public: deba@1408: deba@1408: template deba@1408: EdgeReader(LemonReader& _reader, const Resolver& _resolver, deba@1408: const std::string& _id = std::string()) deba@1408: : id(_id), resolver(new ResolverReader deba@1408: (_resolver)) { deba@1408: _reader.attach(*this); deba@1408: } deba@1408: deba@1408: virtual ~EdgeReader() {} deba@1408: private: deba@1408: EdgeReader(const EdgeReader&); deba@1408: void operator=(const EdgeReader&); deba@1408: deba@1408: public: deba@1408: deba@1408: void readEdge(const std::string& name, Item& item) { deba@1408: if (readers.find(name) != readers.end()) { deba@1408: ErrorMessage msg; deba@1408: msg << "Multiple read rule for edge: " << name; deba@1408: throw IOParameterError(msg.message()); deba@1408: } deba@1408: readers.insert(make_pair(name, &item)); deba@1408: } deba@1408: deba@1408: deba@1408: virtual bool header(const std::string& line) { deba@1408: std::istringstream ls(line); deba@1408: std::string command; deba@1408: std::string name; deba@1408: ls >> command >> name; deba@1408: return command == "@nodes" && name == id; deba@1408: } deba@1408: deba@1408: virtual void read(std::istream& is) { deba@1408: std::string line; deba@1408: while (getline(is, line)) { deba@1408: std::istringstream ls(line); deba@1408: std::string id; deba@1408: ls >> id; deba@1408: typename ItemReaders::iterator it = readers.find(id); deba@1408: if (it != readers.end()) { deba@1408: *(it->second) = resolver->resolve(ls); deba@1408: } deba@1408: } deba@1408: } deba@1408: deba@1408: private: deba@1408: deba@1408: std::string id; deba@1408: deba@1408: typedef std::map ItemReaders; deba@1408: ItemReaders readers; deba@1408: std::auto_ptr > resolver; deba@1408: }; deba@1408: deba@1408: /// \e deba@1408: class PrintReader : public LemonReader::SectionReader { deba@1408: typedef LemonReader::SectionReader Parent; deba@1408: public: deba@1408: deba@1408: /// \e deba@1408: PrintReader(LemonReader& reader) { deba@1408: reader.attach(*this); deba@1408: } deba@1408: deba@1408: /// \e deba@1408: bool header(const std::string& line) { deba@1408: std::cout << "Asked header: " << line << std::endl; deba@1408: return true; deba@1408: } deba@1408: deba@1408: /// \e deba@1408: void read(std::istream& is) { deba@1408: std::string line; deba@1408: while (std::getline(is, line)) { deba@1408: std::cout << line << std::endl; deba@1408: } deba@1408: } deba@1408: deba@1408: }; deba@1408: deba@1408: /// @} deba@1408: } deba@1408: #endif