diff -r e1dd2a70737c -r 1c9a9e2f7d4d lemon/lgf_reader.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/lemon/lgf_reader.h Thu Apr 17 15:18:45 2008 +0100 @@ -0,0 +1,914 @@ +/* -*- C++ -*- + * + * This file is a part of LEMON, a generic C++ optimization library + * + * Copyright (C) 2003-2008 + * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport + * (Egervary Research Group on Combinatorial Optimization, EGRES). + * + * Permission to use, modify and distribute this software is granted + * provided that this copyright notice appears in all copies. For + * precise terms see the accompanying LICENSE file. + * + * This software is provided "AS IS" with no warranty of any kind, + * express or implied, and with no claim as to its suitability for any + * purpose. + * + */ + +///\ingroup lemon_io +///\file +///\brief Lemon Graph Format reader. + + +#ifndef LEMON_LGF_READER_H +#define LEMON_LGF_READER_H + +#include +#include +#include + +#include +#include + +#include +#include + +#include + +#include +#include + +namespace lemon { + + namespace _reader_bits { + + template + struct DefaultConverter { + Value operator()(const std::string& str) { + std::istringstream is(str); + Value value; + is >> value; + + char c; + if (is >> std::ws >> c) { + throw DataFormatError("Remaining characters in token"); + } + return value; + } + }; + + template <> + struct DefaultConverter { + std::string operator()(const std::string& str) { + return str; + } + }; + + template + class MapStorageBase { + public: + typedef _Item Item; + + public: + MapStorageBase() {} + virtual ~MapStorageBase() {} + + virtual void set(const Item& item, const std::string& value) = 0; + + }; + + template > + class MapStorage : public MapStorageBase<_Item> { + public: + typedef _Map Map; + typedef _Converter Converter; + typedef _Item Item; + + private: + Map& _map; + Converter _converter; + + public: + MapStorage(Map& map, const Converter& converter = Converter()) + : _map(map), _converter(converter) {} + virtual ~MapStorage() {} + + virtual void set(const Item& item ,const std::string& value) { + _map.set(item, _converter(value)); + } + }; + + class ValueStorageBase { + public: + ValueStorageBase() {} + virtual ~ValueStorageBase() {} + + virtual void set(const std::string&) = 0; + }; + + template > + class ValueStorage : public ValueStorageBase { + public: + typedef _Value Value; + typedef _Converter Converter; + + private: + Value& _value; + Converter _converter; + + public: + ValueStorage(Value& value, const Converter& converter = Converter()) + : _value(value), _converter(converter) {} + + virtual void set(const std::string& value) { + _value = _converter(value); + } + }; + + template + struct MapLookUpConverter { + const std::map& _map; + + MapLookUpConverter(const std::map& map) + : _map(map) {} + + Value operator()(const std::string& str) { + typename std::map::const_iterator it = + _map.find(str); + if (it == _map.end()) { + std::ostringstream msg; + msg << "Item not found: " << str; + throw DataFormatError(msg.str().c_str()); + } + return it->second; + } + }; + + bool isWhiteSpace(char c) { + return c == ' ' || c == '\t' || c == '\v' || + c == '\n' || c == '\r' || c == '\f'; + } + + bool isOct(char c) { + return '0' <= c && c <='7'; + } + + int valueOct(char c) { + LEMON_ASSERT(isOct(c), "The character is not octal."); + return c - '0'; + } + + bool isHex(char c) { + return ('0' <= c && c <= '9') || + ('a' <= c && c <= 'z') || + ('A' <= c && c <= 'Z'); + } + + int valueHex(char c) { + LEMON_ASSERT(isHex(c), "The character is not hexadecimal."); + if ('0' <= c && c <= '9') return c - '0'; + if ('a' <= c && c <= 'z') return c - 'a' + 10; + return c - 'A' + 10; + } + + bool isIdentifierFirstChar(char c) { + return ('a' <= c && c <= 'z') || + ('A' <= c && c <= 'Z') || c == '_'; + } + + bool isIdentifierChar(char c) { + return isIdentifierFirstChar(c) || + ('0' <= c && c <= '9'); + } + + char readEscape(std::istream& is) { + char c; + if (!is.get(c)) + throw DataFormatError("Escape format error"); + + switch (c) { + case '\\': + return '\\'; + case '\"': + return '\"'; + case '\'': + return '\''; + case '\?': + return '\?'; + case 'a': + return '\a'; + case 'b': + return '\b'; + case 'f': + return '\f'; + case 'n': + return '\n'; + case 'r': + return '\r'; + case 't': + return '\t'; + case 'v': + return '\v'; + case 'x': + { + int code; + if (!is.get(c) || !isHex(c)) + throw DataFormatError("Escape format error"); + else if (code = valueHex(c), !is.get(c) || !isHex(c)) is.putback(c); + else code = code * 16 + valueHex(c); + return code; + } + default: + { + int code; + if (!isOct(c)) + throw DataFormatError("Escape format error"); + else if (code = valueOct(c), !is.get(c) || !isOct(c)) + is.putback(c); + else if (code = code * 8 + valueOct(c), !is.get(c) || !isOct(c)) + is.putback(c); + else code = code * 8 + valueOct(c); + return code; + } + } + } + + std::istream& readToken(std::istream& is, std::string& str) { + std::ostringstream os; + + char c; + is >> std::ws; + + if (!is.get(c)) + return is; + + if (c == '\"') { + while (is.get(c) && c != '\"') { + if (c == '\\') + c = readEscape(is); + os << c; + } + if (!is) + throw DataFormatError("Quoted format error"); + } else { + is.putback(c); + while (is.get(c) && !isWhiteSpace(c)) { + if (c == '\\') + c = readEscape(is); + os << c; + } + if (!is) { + is.clear(); + } else { + is.putback(c); + } + } + str = os.str(); + return is; + } + + std::istream& readIdentifier(std::istream& is, std::string& str) { + std::ostringstream os; + + char c; + is >> std::ws; + + if (!is.get(c)) + return is; + + if (!isIdentifierFirstChar(c)) + throw DataFormatError("Wrong char in identifier"); + + os << c; + + while (is.get(c) && !isWhiteSpace(c)) { + if (!isIdentifierChar(c)) + throw DataFormatError("Wrong char in identifier"); + os << c; + } + if (!is) is.clear(); + + str = os.str(); + return is; + } + + } + + /// \e + template + class DigraphReader { + public: + + typedef _Digraph Digraph; + GRAPH_TYPEDEFS(typename Digraph); + + private: + + + std::istream* _is; + bool local_is; + + Digraph& _digraph; + + std::string _nodes_caption; + std::string _arcs_caption; + std::string _attributes_caption; + + typedef std::map NodeIndex; + NodeIndex _node_index; + typedef std::map ArcIndex; + ArcIndex _arc_index; + + typedef std::vector*> > NodeMaps; + NodeMaps _node_maps; + + typedef std::vector*> >ArcMaps; + ArcMaps _arc_maps; + + typedef std::multimap + Attributes; + Attributes _attributes; + + bool _use_nodes; + bool _use_arcs; + + int line_num; + std::istringstream line; + + public: + + /// \e + DigraphReader(std::istream& is, Digraph& digraph) + : _is(&is), local_is(false), _digraph(digraph), + _use_nodes(false), _use_arcs(false) {} + + /// \e + DigraphReader(const std::string& fn, Digraph& digraph) + : _is(new std::ifstream(fn.c_str())), local_is(true), _digraph(digraph), + _use_nodes(false), _use_arcs(false) {} + + + /// \e + DigraphReader(const char* fn, Digraph& digraph) + : _is(new std::ifstream(fn)), local_is(true), _digraph(digraph), + _use_nodes(false), _use_arcs(false) {} + + /// \e + DigraphReader(DigraphReader& other) + : _is(other._is), local_is(other.local_is), _digraph(other._digraph), + _use_nodes(other._use_nodes), _use_arcs(other._use_arcs) { + + other.is = 0; + other.local_is = false; + + _node_index.swap(other._node_index); + _arc_index.swap(other._arc_index); + + _node_maps.swap(other._node_maps); + _arc_maps.swap(other._arc_maps); + _attributes.swap(other._attributes); + + _nodes_caption = other._nodes_caption; + _arcs_caption = other._arcs_caption; + _attributes_caption = other._attributes_caption; + } + + /// \e + ~DigraphReader() { + for (typename NodeMaps::iterator it = _node_maps.begin(); + it != _node_maps.end(); ++it) { + delete it->second; + } + + for (typename ArcMaps::iterator it = _arc_maps.begin(); + it != _arc_maps.end(); ++it) { + delete it->second; + } + + for (typename Attributes::iterator it = _attributes.begin(); + it != _attributes.end(); ++it) { + delete it->second; + } + + if (local_is) { + delete _is; + } + + } + + private: + + DigraphReader& operator=(const DigraphReader&); + + public: + + /// \e + template + DigraphReader& nodeMap(const std::string& caption, Map& map) { + checkConcept, Map>(); + _reader_bits::MapStorageBase* storage = + new _reader_bits::MapStorage(map); + _node_maps.push_back(std::make_pair(caption, storage)); + return *this; + } + + /// \e + template + DigraphReader& nodeMap(const std::string& caption, Map& map, + const Converter& converter = Converter()) { + checkConcept, Map>(); + _reader_bits::MapStorageBase* storage = + new _reader_bits::MapStorage(map, converter); + _node_maps.push_back(std::make_pair(caption, storage)); + return *this; + } + + /// \e + template + DigraphReader& arcMap(const std::string& caption, Map& map) { + checkConcept, Map>(); + _reader_bits::MapStorageBase* storage = + new _reader_bits::MapStorage(map); + _arc_maps.push_back(std::make_pair(caption, storage)); + return *this; + } + + /// \e + template + DigraphReader& arcMap(const std::string& caption, Map& map, + const Converter& converter = Converter()) { + checkConcept, Map>(); + _reader_bits::MapStorageBase* storage = + new _reader_bits::MapStorage(map, converter); + _arc_maps.push_back(std::make_pair(caption, storage)); + return *this; + } + + /// \e + template + DigraphReader& attribute(const std::string& caption, Value& value) { + _reader_bits::ValueStorageBase* storage = + new _reader_bits::ValueStorage(value); + _attributes.insert(std::make_pair(caption, storage)); + return *this; + } + + /// \e + template + DigraphReader& attribute(const std::string& caption, Value& value, + const Converter& converter = Converter()) { + _reader_bits::ValueStorageBase* storage = + new _reader_bits::ValueStorage(value, converter); + _attributes.insert(std::make_pair(caption, storage)); + return *this; + } + + /// \e + DigraphReader& node(const std::string& caption, Node& node) { + typedef _reader_bits::MapLookUpConverter Converter; + Converter converter(_node_index); + _reader_bits::ValueStorageBase* storage = + new _reader_bits::ValueStorage(node, converter); + _attributes.insert(std::make_pair(caption, storage)); + return *this; + } + + /// \e + DigraphReader& arc(const std::string& caption, Arc& arc) { + typedef _reader_bits::MapLookUpConverter Converter; + Converter converter(_arc_index); + _reader_bits::ValueStorageBase* storage = + new _reader_bits::ValueStorage(arc, converter); + _attributes.insert(std::make_pair(caption, storage)); + return *this; + } + + /// \e + DigraphReader& nodes(const std::string& caption) { + _nodes_caption = caption; + return *this; + } + + /// \e + DigraphReader& arcs(const std::string& caption) { + _arcs_caption = caption; + return *this; + } + + /// \e + DigraphReader& attributes(const std::string& caption) { + _attributes_caption = caption; + return *this; + } + + /// \e + template + DigraphReader& useNodes(const Map& map) { + checkConcept, Map>(); + LEMON_ASSERT(!_use_nodes, "Multiple usage of useNodes() member"); + _use_nodes = true; + _writer_bits::DefaultConverter converter; + for (NodeIt n(_digraph); n != INVALID; ++n) { + _node_index.insert(std::make_pair(converter(map[n]), n)); + } + return *this; + } + + /// \e + template + DigraphReader& useNodes(const Map& map, + const Converter& converter = Converter()) { + checkConcept, Map>(); + LEMON_ASSERT(!_use_nodes, "Multiple usage of useNodes() member"); + _use_nodes = true; + for (NodeIt n(_digraph); n != INVALID; ++n) { + _node_index.insert(std::make_pair(converter(map[n]), n)); + } + return *this; + } + + /// \e + template + DigraphReader& useArcs(const Map& map) { + checkConcept, Map>(); + LEMON_ASSERT(!_use_arcs, "Multiple usage of useArcs() member"); + _use_arcs = true; + _writer_bits::DefaultConverter converter; + for (ArcIt a(_digraph); a != INVALID; ++a) { + _arc_index.insert(std::make_pair(converter(map[a]), a)); + } + return *this; + } + + /// \e + template + DigraphReader& useArcs(const Map& map, + const Converter& converter = Converter()) { + checkConcept, Map>(); + LEMON_ASSERT(!_use_arcs, "Multiple usage of useArcs() member"); + _use_arcs = true; + for (ArcIt a(_digraph); a != INVALID; ++a) { + _arc_index.insert(std::make_pair(converter(map[a]), a)); + } + return *this; + } + + private: + + bool readLine() { + std::string str; + while(++line_num, std::getline(*_is, str)) { + line.clear(); line.str(str); + char c; + if (line >> std::ws >> c && c != '#') { + line.putback(c); + return true; + } + } + return false; + } + + bool readSuccess() { + return static_cast(*_is); + } + + void skipSection() { + char c; + while (readSuccess() && line >> c && c != '@') { + readLine(); + } + line.putback(c); + } + + void readNodes() { + + std::vector map_index(_node_maps.size()); + int map_num, label_index; + + if (!readLine()) + throw DataFormatError("Cannot find map captions"); + + { + std::map maps; + + std::string map; + int index = 0; + while (_reader_bits::readIdentifier(line, map)) { + if (maps.find(map) != maps.end()) { + std::ostringstream msg; + msg << "Multiple occurence of node map: " << map; + throw DataFormatError(msg.str().c_str()); + } + maps.insert(std::make_pair(map, index)); + ++index; + } + + for (int i = 0; i < static_cast(_node_maps.size()); ++i) { + std::map::iterator jt = + maps.find(_node_maps[i].first); + if (jt == maps.end()) { + std::ostringstream msg; + msg << "Map not found in file: " << _node_maps[i].first; + throw DataFormatError(msg.str().c_str()); + } + map_index[i] = jt->second; + } + + { + std::map::iterator jt = maps.find("label"); + if (jt == maps.end()) + throw DataFormatError("Label map not found in file"); + label_index = jt->second; + } + map_num = maps.size(); + } + + char c; + while (readLine() && line >> c && c != '@') { + line.putback(c); + + std::vector tokens(map_num); + for (int i = 0; i < map_num; ++i) { + if (!_reader_bits::readToken(line, tokens[i])) { + std::ostringstream msg; + msg << "Column not found (" << i + 1 << ")"; + throw DataFormatError(msg.str().c_str()); + } + } + if (line >> std::ws >> c) + throw DataFormatError("Extra character on the end of line"); + + Node n; + if (!_use_nodes) { + n = _digraph.addNode(); + _node_index.insert(std::make_pair(tokens[label_index], n)); + } else { + typename std::map::iterator it = + _node_index.find(tokens[label_index]); + if (it == _node_index.end()) { + std::ostringstream msg; + msg << "Node with label not found: " << tokens[label_index]; + throw DataFormatError(msg.str().c_str()); + } + n = it->second; + } + + for (int i = 0; i < static_cast(_node_maps.size()); ++i) { + _node_maps[i].second->set(n, tokens[map_index[i]]); + } + + } + if (readSuccess()) { + line.putback(c); + } + } + + void readArcs() { + + std::vector map_index(_arc_maps.size()); + int map_num, label_index; + + if (!readLine()) + throw DataFormatError("Cannot find map captions"); + + { + std::map maps; + + std::string map; + int index = 0; + while (_reader_bits::readIdentifier(line, map)) { + if (maps.find(map) != maps.end()) { + std::ostringstream msg; + msg << "Multiple occurence of arc map: " << map; + throw DataFormatError(msg.str().c_str()); + } + maps.insert(std::make_pair(map, index)); + ++index; + } + + for (int i = 0; i < static_cast(_arc_maps.size()); ++i) { + std::map::iterator jt = + maps.find(_arc_maps[i].first); + if (jt == maps.end()) { + std::ostringstream msg; + msg << "Map not found in file: " << _arc_maps[i].first; + throw DataFormatError(msg.str().c_str()); + } + map_index[i] = jt->second; + } + + { + std::map::iterator jt = maps.find("label"); + if (jt == maps.end()) + throw DataFormatError("Label map not found in file"); + label_index = jt->second; + } + map_num = maps.size(); + } + + char c; + while (readLine() && line >> c && c != '@') { + line.putback(c); + + std::string source_token; + std::string target_token; + + if (!_reader_bits::readToken(line, source_token)) + throw DataFormatError("Source not found"); + + if (!_reader_bits::readToken(line, target_token)) + throw DataFormatError("Source not found"); + + std::vector tokens(map_num); + for (int i = 0; i < map_num; ++i) { + if (!_reader_bits::readToken(line, tokens[i])) { + std::ostringstream msg; + msg << "Column not found (" << i + 1 << ")"; + throw DataFormatError(msg.str().c_str()); + } + } + if (line >> std::ws >> c) + throw DataFormatError("Extra character on the end of line"); + + Arc a; + if (!_use_arcs) { + + typename NodeIndex::iterator it; + + it = _node_index.find(source_token); + if (it == _node_index.end()) { + std::ostringstream msg; + msg << "Item not found: " << source_token; + throw DataFormatError(msg.str().c_str()); + } + Node source = it->second; + + it = _node_index.find(target_token); + if (it == _node_index.end()) { + std::ostringstream msg; + msg << "Item not found: " << target_token; + throw DataFormatError(msg.str().c_str()); + } + Node target = it->second; + + a = _digraph.addArc(source, target); + _arc_index.insert(std::make_pair(tokens[label_index], a)); + } else { + typename std::map::iterator it = + _arc_index.find(tokens[label_index]); + if (it == _arc_index.end()) { + std::ostringstream msg; + msg << "Arc with label not found: " << tokens[label_index]; + throw DataFormatError(msg.str().c_str()); + } + a = it->second; + } + + for (int i = 0; i < static_cast(_arc_maps.size()); ++i) { + _arc_maps[i].second->set(a, tokens[map_index[i]]); + } + + } + if (readSuccess()) { + line.putback(c); + } + } + + void readAttributes() { + + std::set read_attr; + + char c; + while (readLine() && line >> c && c != '@') { + line.putback(c); + + std::string attr, token; + if (!_reader_bits::readIdentifier(line, attr)) + throw DataFormatError("Attribute name not found"); + if (!_reader_bits::readToken(line, token)) + throw DataFormatError("Attribute value not found"); + if (line >> c) + throw DataFormatError("Extra character on the end of line"); + + { + std::set::iterator it = read_attr.find(attr); + if (it != read_attr.end()) { + std::ostringstream msg; + msg << "Multiple occurence of attribute " << attr; + throw DataFormatError(msg.str().c_str()); + } + read_attr.insert(attr); + } + + { + typename Attributes::iterator it = _attributes.lower_bound(attr); + while (it != _attributes.end() && it->first == attr) { + it->second->set(token); + ++it; + } + } + + } + if (readSuccess()) { + line.putback(c); + } + for (typename Attributes::iterator it = _attributes.begin(); + it != _attributes.end(); ++it) { + if (read_attr.find(it->first) == read_attr.end()) { + std::ostringstream msg; + msg << "Attribute not found in file: " << it->first; + throw DataFormatError(msg.str().c_str()); + } + } + } + + public: + + /// \e + void run() { + + LEMON_ASSERT(_is != 0, "This reader assigned to an other reader"); + + bool nodes_done = false; + bool arcs_done = false; + bool attributes_done = false; + + line_num = 0; + readLine(); + + while (readSuccess()) { + skipSection(); + try { + char c; + std::string section, caption; + line >> c; + _reader_bits::readIdentifier(line, section); + _reader_bits::readIdentifier(line, caption); + + if (line >> c) + throw DataFormatError("Extra character on the end of line"); + + if (section == "nodes" && !nodes_done) { + if (_nodes_caption.empty() || _nodes_caption == caption) { + readNodes(); + nodes_done = true; + } + } else if ((section == "arcs" || section == "edges") && + !arcs_done) { + if (_arcs_caption.empty() || _arcs_caption == caption) { + readArcs(); + arcs_done = true; + } + } else if (section == "attributes" && !attributes_done) { + if (_attributes_caption.empty() || _attributes_caption == caption) { + readAttributes(); + attributes_done = true; + } + } else { + readLine(); + skipSection(); + } + } catch (DataFormatError& error) { + error.line(line_num); + throw; + } + } + + if (!nodes_done) { + throw DataFormatError("Section @nodes not found"); + } + + if (!arcs_done) { + throw DataFormatError("Section @arcs not found"); + } + + if (!attributes_done && !_attributes.empty()) { + throw DataFormatError("Section @attributes not found"); + } + + } + + }; + + template + DigraphReader digraphReader(std::istream& is, Digraph& digraph) { + return DigraphReader(is, digraph); + } + + template + DigraphReader digraphReader(const std::string& fn, + Digraph& digraph) { + return DigraphReader(fn, digraph); + } + + template + DigraphReader digraphReader(const char* fn, Digraph& digraph) { + return DigraphReader(fn, digraph); + } +} + +#endif