deba@1408: /* -*- C++ -*- deba@1408: * alpar@1956: * This file is a part of LEMON, a generic C++ optimization library alpar@1956: * alpar@2553: * Copyright (C) 2003-2008 alpar@1956: * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport alpar@1956: * (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: alpar@1946: /// \ingroup item_io deba@1408: /// \file deba@1408: /// \brief Item reader bits for lemon input. deba@1408: deba@1408: #ifndef LEMON_BITS_ITEM_READER_H deba@1408: #define LEMON_BITS_ITEM_READER_H deba@1408: deba@1408: #include deba@1408: #include deba@1408: deba@1408: #include deba@1408: #include deba@1408: #include deba@1408: #include deba@2426: #include deba@2426: deba@2426: #include deba@1408: deba@1408: namespace lemon { deba@1408: deba@1408: template deba@1408: class DefaultReader; deba@1408: alpar@1946: /// \ingroup item_io deba@1408: /// deba@2254: /// \brief Reader class for unformatted strings. deba@2254: /// deba@2254: /// Reader class for unformatted strings. This class want to be deba@2254: /// a general reader type which can read the most deba@2254: /// deba@2254: /// \author Balazs Dezso deba@2254: class UnformattedReader { deba@2254: public: deba@2254: /// \brief The value type of reader. deba@2254: /// deba@2254: /// The value type of reader. deba@2254: typedef std::string Value; deba@2254: deba@2254: /// \brief Constructor for the reader. deba@2254: /// deba@2254: /// Constructor for the reader. deba@2254: UnformattedReader() {} deba@2254: deba@2254: /// \brief Reads an unformatted string from the given stream. deba@2254: /// deba@2254: /// Reads an unformatted string from the given stream. deba@2254: void read(std::istream& is, std::string& value) const { deba@2254: char c; deba@2254: value.clear(); deba@2254: is >> std::ws; deba@2254: while (is.get(c) && !whiteSpace(c)) { deba@2254: processChar(c, is, value); deba@2254: } deba@2254: } deba@2254: deba@2254: private: deba@2254: deba@2254: void processChar(char c, std::istream& is, Value& value) const { deba@2254: switch (c) { deba@2254: case '(': deba@2254: is.putback(c); deba@2254: readParsed('(', ')', is, value); deba@2254: break; deba@2254: case '[': deba@2254: is.putback(c); deba@2254: readParsed('[', ']', is, value); deba@2254: break; deba@2254: case '{': deba@2254: is.putback(c); deba@2254: readParsed('{', '}', is, value); deba@2254: break; deba@2254: case '/': deba@2254: is.putback(c); deba@2254: readParsed('/', '/', is, value); deba@2254: break; deba@2254: case '\"': deba@2254: is.putback(c); deba@2254: readQuoted('\"', is, value); deba@2254: break; deba@2254: case '\'': deba@2254: is.putback(c); deba@2254: readQuoted('\'', is, value); deba@2254: break; deba@2254: default: deba@2254: value += c; deba@2254: break; deba@2254: } deba@2254: } deba@2254: deba@2254: void readParsed(char open, char close, deba@2254: std::istream& is, Value& value) const { deba@2254: char c; deba@2254: if (!is.get(c) || c != open) deba@2254: throw DataFormatError("Unformatted string format error"); deba@2254: value += c; deba@2254: while (is.get(c) && c != close) { deba@2254: processChar(c, is, value); deba@2254: } deba@2254: if (!is) deba@2254: throw DataFormatError("Unformatted string format error"); deba@2254: value += c; deba@2254: } deba@2254: deba@2254: void readQuoted(char quote, std::istream& is, Value& value) const { deba@2254: char c; deba@2254: bool esc = false; deba@2254: if (!is.get(c) || c != quote) deba@2254: throw DataFormatError("Unformatted string format error"); deba@2254: value += c; deba@2254: while (is.get(c) && (c != quote || esc)) { deba@2254: if (c == '\\') esc = !esc; deba@2254: else esc = false; deba@2254: value += c; deba@2254: } deba@2254: if (!is) deba@2254: throw DataFormatError("Unformatted string format error"); deba@2254: value += c; deba@2254: } deba@2254: deba@2254: deba@2254: deba@2254: static bool whiteSpace(char c) { deba@2254: return c == ' ' || c == '\t' || c == '\v' || deba@2254: c == '\n' || c == '\r' || c == '\f'; deba@2254: } deba@2254: deba@2254: deba@2254: }; deba@2254: deba@2254: /// \ingroup item_io deba@2254: /// deba@1408: /// \brief Reader class for quoted strings. deba@1408: /// deba@1408: /// Reader class for quoted strings. It can process the escape deba@1408: /// sequences in the string. deba@1408: /// deba@1408: /// \author Balazs Dezso deba@1408: class QuotedStringReader { deba@2254: friend class QuotedCharReader; deba@1408: public: deba@1408: /// \brief The value type of reader. deba@1408: /// deba@1408: /// The value type of reader. deba@1408: typedef std::string Value; deba@1408: deba@1408: /// \brief Constructor for the reader. deba@1408: /// deba@1408: /// Constructor for the reader. If the given parameter is true deba@1408: /// the reader processes the escape sequences. deba@1408: QuotedStringReader(bool _escaped = true) deba@1408: : escaped(_escaped) {} deba@1408: deba@1408: /// \brief Reads a quoted string from the given stream. deba@1408: /// deba@1408: /// Reads a quoted string from the given stream. deba@1408: void read(std::istream& is, std::string& value) const { deba@1408: char c; deba@1408: value.clear(); deba@1408: is >> std::ws; deba@2426: if (!is.get(c) || (c != '\"' && c != '\'')) deba@2254: throw DataFormatError("Quoted format error"); deba@2426: char quote = c; deba@2426: while (is.get(c) && c != quote) { deba@1408: if (escaped && c == '\\') { deba@1408: value += readEscape(is); deba@1408: } else { deba@1408: value += c; deba@1408: } deba@1408: } deba@2254: if (!is) throw DataFormatError("Quoted format error"); deba@1408: } deba@1408: deba@1408: private: deba@1408: deba@1408: static char readEscape(std::istream& is) { deba@1408: char c; deba@1408: switch (is.get(c), c) { deba@1408: case '\\': deba@1408: return '\\'; deba@1408: case '\"': deba@1408: return '\"'; deba@1408: case '\'': deba@1408: return '\''; deba@1408: case '\?': deba@1408: return '\?'; deba@1408: case 'a': deba@1408: return '\a'; deba@1408: case 'b': deba@1408: return '\b'; deba@1408: case 'f': deba@1408: return '\f'; deba@1408: case 'n': deba@1408: return '\n'; deba@1408: case 'r': deba@1408: return '\r'; deba@1408: case 't': deba@1408: return '\t'; deba@1408: case 'v': deba@1408: return '\v'; deba@1408: case 'x': deba@1408: { deba@1408: int code; deba@1408: if (!is.get(c) || !isHex(c)) deba@1408: throw DataFormatError("Escape format error"); deba@1408: else if (code = valueHex(c), !is.get(c) || !isHex(c)) is.putback(c); deba@1408: else code = code * 16 + valueHex(c); deba@1408: return code; deba@1408: } deba@1408: default: deba@1408: { deba@1408: int code; deba@1408: if (!isOct(c)) deba@1408: throw DataFormatError("Escape format error"); deba@1408: else if (code = valueOct(c), !is.get(c) || !isOct(c)) deba@1408: is.putback(c); deba@1408: else if (code = code * 8 + valueOct(c), !is.get(c) || !isOct(c)) deba@1408: is.putback(c); deba@1408: else code = code * 8 + valueOct(c); deba@1408: return code; deba@1408: } deba@1408: } deba@1408: } deba@1408: deba@1408: static bool isOct(char c) { deba@1408: return '0' <= c && c <='7'; deba@1408: } deba@1408: deba@1408: static int valueOct(char c) { deba@1408: return c - '0'; deba@1408: } deba@1408: deba@1408: static bool isHex(char c) { deba@1408: return ('0' <= c && c <= '9') || deba@1408: ('a' <= c && c <= 'z') || deba@1408: ('A' <= c && c <= 'Z'); deba@1408: } deba@1408: deba@1408: static int valueHex(char c) { deba@1408: if ('0' <= c && c <= '9') return c - '0'; deba@1408: if ('a' <= c && c <= 'z') return c - 'a' + 10; deba@1408: return c - 'A' + 10; deba@1408: } deba@1408: deba@1408: bool escaped; deba@1408: }; deba@1408: alpar@1946: /// \ingroup item_io deba@2254: /// deba@2254: /// \brief Reader class for quoted strings. deba@2254: /// deba@2254: /// Reader class for quoted strings. It can process the escape deba@2254: /// sequences in the string. deba@2254: /// deba@2254: /// \author Balazs Dezso deba@2254: class QuotedCharReader { deba@2254: public: deba@2254: /// \brief The value type of reader. deba@2254: /// deba@2254: /// The value type of reader. deba@2254: typedef char Value; deba@2254: deba@2254: /// \brief Constructor for the reader. deba@2254: /// deba@2254: /// Constructor for the reader. If the given parameter is true deba@2254: /// the reader processes the escape sequences. deba@2254: QuotedCharReader(bool _escaped = true) deba@2254: : escaped(_escaped) {} deba@2254: deba@2254: /// \brief Reads a quoted string from the given stream. deba@2254: /// deba@2254: /// Reads a quoted string from the given stream. deba@2254: void read(std::istream& is, char& value) const { deba@2254: char c; deba@2254: is >> std::ws; deba@2254: if (!is.get(c) || c != '\'') deba@2254: throw DataFormatError("Quoted format error"); deba@2254: if (!is.get(c)) deba@2254: throw DataFormatError("Quoted format error"); deba@2254: if (escaped && c == '\\') { deba@2254: value = QuotedStringReader::readEscape(is); deba@2254: } else { deba@2254: value = c; deba@2254: } deba@2254: if (!is.get(c) || c != '\'') deba@2254: throw DataFormatError("Quoted format error"); deba@2254: } deba@2254: deba@2254: private: deba@2254: bool escaped; deba@2254: }; deba@2254: deba@2254: /// \ingroup item_io deba@1408: /// \brief Reader for standard containers. deba@1408: /// deba@1408: /// Reader for back insertable standard containers. The representation deba@1408: /// of the container is the values enumerated between an open and a deba@1408: /// close parse. deba@1408: /// deba@1408: /// \author Balazs Dezso deba@1408: template < deba@1408: typename _Container, deba@1408: typename _ItemReader = DefaultReader deba@1408: > deba@1408: class PushBackReader { deba@1408: public: deba@1408: typedef _Container Value; deba@1408: typedef _ItemReader ItemReader; deba@1408: deba@1408: private: deba@1408: deba@1408: ItemReader item_reader; deba@1408: deba@1408: public: deba@1408: deba@1852: /// \brief Constructor for InsertReader deba@1852: /// deba@1852: /// Constructor for InsertReader deba@1852: PushBackReader(const ItemReader& _item_reader = ItemReader()) deba@1852: : item_reader(_item_reader) {} deba@1852: deba@1408: /// \brief Reads the values into the container from the given stream. deba@1408: /// deba@1408: /// Reads the values into the container from the given stream. deba@1408: void read(std::istream& is, Value& value) const { deba@1408: char c; deba@1408: if (!(is >> c) || c != '(') deba@1408: throw DataFormatError("PushBackReader format error"); deba@1408: while (is >> c && c != ')') { deba@1408: is.putback(c); deba@1408: typename ItemReader::Value item; deba@1408: item_reader.read(is, item); deba@1408: value.push_back(item); deba@1408: } deba@1408: if (!is) throw DataFormatError("PushBackReader format error"); deba@1408: } deba@1408: deba@1408: }; deba@1408: alpar@1946: /// \ingroup item_io deba@1408: /// deba@1408: /// \brief Reader for standard containers. deba@1408: /// deba@1408: /// Reader for insertable standard containers. The representation deba@1408: /// of the container is the values enumerated between an open and a deba@1408: /// close parse. deba@1408: /// deba@1408: /// \author Balazs Dezso deba@1408: template < deba@1408: typename _Container, deba@1408: typename _ItemReader = DefaultReader deba@1408: > deba@1408: class InsertReader { deba@1408: public: deba@1408: typedef _Container Value; deba@1408: typedef _ItemReader ItemReader; deba@1408: deba@1408: private: deba@1408: deba@1408: ItemReader item_reader; deba@1408: deba@1408: public: deba@1408: deba@1852: /// \brief Constructor for InsertReader deba@1852: /// deba@1852: /// Constructor for InsertReader deba@1852: InsertReader(const ItemReader& _item_reader = ItemReader()) deba@1852: : item_reader(_item_reader) {} deba@1852: deba@1408: /// \brief Reads the values into the container from the given stream. deba@1408: /// deba@1408: /// Reads the values into the container from the given stream. deba@1408: void read(std::istream& is, Value& value) const { deba@1408: char c; deba@1408: if (!(is >> c) || c != '(') deba@1408: throw DataFormatError("InsertReader format error"); deba@1408: while (is >> c && c != ')') { deba@1408: is.putback(c); deba@1408: typename ItemReader::Value item; deba@1408: item_reader.read(is, item); deba@1408: value.insert(item); deba@1408: } deba@1408: if (!is) throw DataFormatError("PushBackReader format error"); deba@1408: } deba@1408: deba@1408: }; deba@1408: alpar@1946: /// \ingroup item_io deba@1408: /// \brief Reader for parsed string. deba@1408: /// deba@1744: /// Reader for parsed strings. You can define the open and close deba@1744: /// parse characters. It reads from the input a character sequence deba@1744: /// which is right parsed. deba@1408: /// deba@1408: /// \author Balazs Dezso deba@1408: class ParsedStringReader { deba@1408: public: deba@1408: typedef std::string Value; deba@1408: deba@1408: /// \brief Constructor. deba@1408: /// deba@1408: /// Constructor for ParsedStringReader. You can give as parameter deba@1408: /// the open and close parse characters. deba@1408: ParsedStringReader(char _open = '(', char _close = ')') deba@1408: : open(_open), close(_close) {} deba@1408: deba@1408: deba@1408: /// \brief Reads the parsed string from the given stream. deba@1408: /// deba@1408: /// Reads the parsed string from the given stream. deba@1408: void read(std::istream& is, Value& value) const { deba@1408: char c; deba@2254: value.clear(); deba@1408: if (!(is >> c) || c != open) { deba@1408: throw DataFormatError("ParsedStringReader format error"); deba@1408: } deba@1408: value += c; deba@1408: int counter = 1; deba@1408: while (counter > 0 && is >> c) { deba@1408: if (c == close) { deba@1408: --counter; deba@1408: } else if (c == open) { deba@1408: ++counter; deba@1408: } deba@1408: value += c; deba@1408: } deba@1408: if (!is) { deba@1408: throw DataFormatError("ParsedStrinReader format error"); deba@1408: } deba@1408: } deba@1408: deba@1408: private: deba@1408: char open, close; deba@1408: deba@1408: }; deba@1408: alpar@1946: /// \ingroup item_io deba@1408: /// \brief Reader for read the whole line. deba@1408: /// deba@1408: /// Reader for read the whole line. deba@1408: /// deba@1408: /// \author Balazs Dezso deba@1408: class LineReader { deba@1408: public: deba@1408: typedef std::string Value; deba@1408: deba@1408: /// \brief Constructor. deba@1408: /// deba@1408: /// Constructor for the LineReader. If the given parameter is deba@1408: /// true then the spaces before the first not space character are deba@1408: /// skipped. deba@1408: LineReader(bool _skipSpaces = true) : skipSpaces(_skipSpaces) {} deba@1408: deba@1408: /// \brief Reads the line from the given stream. deba@1408: /// deba@1408: /// Reads the line from the given stream. deba@1852: void read(std::istream& is, Value& value) const { deba@1408: if (skipSpaces) is >> std::ws; deba@1408: if (!getline(is, value)) { deba@1852: throw DataFormatError("LineReader format error"); deba@1408: } deba@1408: } deba@1408: private: deba@1408: bool skipSpaces; deba@1408: }; deba@1408: alpar@1946: /// \ingroup item_io deba@1852: /// \brief Reader for std::pair. deba@1852: /// deba@1852: /// Reader for std::pair. deba@1852: /// deba@1852: /// \author Balazs Dezso deba@1852: template , deba@1852: typename _SecondReader = deba@1852: DefaultReader > deba@1852: class PairReader { deba@1852: public: deba@1852: typedef _Pair Value; deba@1852: deba@1852: typedef _FirstReader FirstReader; deba@1852: typedef _SecondReader SecondReader; deba@1852: deba@1852: private: deba@1852: deba@1852: FirstReader first_reader; deba@1852: SecondReader second_reader; deba@1852: deba@1852: public: deba@1852: deba@1852: /// \brief Constructor. deba@1852: /// deba@1852: /// Constructor for the PairReader. deba@1852: PairReader(const FirstReader& _first_reader = FirstReader(), deba@1852: const SecondReader& _second_reader = SecondReader()) deba@1852: : first_reader(_first_reader), second_reader(_second_reader) {} deba@1852: deba@1852: /// \brief Reads the pair from the given stream. deba@1852: /// deba@1852: /// Reads the pair from the given stream. deba@1852: void read(std::istream& is, Value& value) const { deba@1852: char c; deba@1852: if (!(is >> c) || c != '(') { deba@1852: throw DataFormatError("PairReader format error"); deba@1852: } deba@1852: first_reader.read(is, value.first); deba@1852: if (!(is >> c) || c != '=') { deba@1852: throw DataFormatError("PairReader format error"); deba@1852: } deba@1852: if (!(is >> c) || c != '>') { deba@1852: throw DataFormatError("PairReader format error"); deba@1852: } deba@1852: second_reader.read(is, value.second); deba@1852: if (!(is >> c) || c != ')') { deba@1852: throw DataFormatError("PairReader format error"); deba@1852: } deba@1852: } deba@1852: }; deba@1852: alpar@1946: /// \ingroup item_io deba@1408: /// deba@1408: /// \brief The default item reader template class. deba@1408: /// deba@1408: /// The default item reader template class. If some section reader deba@1408: /// needs to read a value from a stream it will give the default way for it. deba@1408: /// deba@1408: /// \author Balazs Dezso deba@1408: template deba@1408: class DefaultReader { deba@1408: public: deba@1408: /// The value type. deba@1408: typedef _Value Value; deba@1408: /// \brief Reads a value from the given stream. deba@1408: /// deba@1408: /// Reads a value from the given stream. deba@1408: void read(std::istream& is, Value& value) const { deba@1408: if (!(is >> value)) deba@1408: throw DataFormatError("DefaultReader format error"); deba@1408: } deba@1408: }; deba@1408: deba@1427: template <> deba@1427: class DefaultReader { deba@1427: public: deba@1427: typedef std::string Value; deba@1427: deba@1427: void read(std::istream& is, Value& value) const { deba@1427: char c; deba@2254: if (!(is >> std::ws >> c)) deba@2254: throw DataFormatError("DefaultReader format error"); deba@1427: is.putback(c); deba@1427: switch (c) { deba@1427: case '\"': deba@1427: QuotedStringReader().read(is, value); deba@1427: break; deba@1427: default: deba@2254: UnformattedReader().read(is, value); deba@1427: break; deba@1427: } deba@1427: } deba@1427: deba@1427: }; deba@1427: deba@2254: template <> deba@2254: class DefaultReader { deba@2254: public: deba@2254: typedef char Value; deba@2254: deba@2254: void read(std::istream& is, Value& value) const { deba@2254: char c; deba@2254: if (!(is >> std::ws >> c)) deba@2254: throw DataFormatError("DefaultReader format error"); deba@2254: is.putback(c); deba@2254: switch (c) { deba@2254: case '\'': deba@2254: QuotedCharReader().read(is, value); deba@2254: break; deba@2254: default: deba@2254: { deba@2254: int temp; deba@2254: if (!(is >> temp)) deba@2254: throw DataFormatError("DefaultReader format error"); deba@2386: value = static_cast(temp); deba@2254: break; deba@2254: } deba@2254: } deba@2254: } deba@2254: }; deba@2254: deba@2254: template <> deba@2254: class DefaultReader { deba@2254: public: deba@2254: typedef bool Value; deba@2254: deba@2254: void read(std::istream& is, Value& value) const { deba@2254: std::string rep; deba@2254: if (!(is >> rep)) deba@2254: throw DataFormatError("DefaultReader format error"); deba@2254: if (rep == "true" || rep == "t" || rep == "1") { deba@2254: value = true; deba@2254: } else if (rep == "false" || rep == "f" || rep == "0") { deba@2254: value = false; deba@2254: } else throw DataFormatError("DefaultReader format error"); deba@2254: } deba@2254: }; deba@2254: deba@1408: template deba@1408: class DefaultReader > deba@1408: : public PushBackReader > {}; deba@1408: deba@1408: template deba@1408: class DefaultReader > deba@1408: : public PushBackReader > {}; deba@1408: deba@1408: template deba@1408: class DefaultReader > deba@1408: : public PushBackReader > {}; deba@1408: deba@1408: template deba@1408: class DefaultReader > deba@1408: : public InsertReader > {}; deba@1408: deba@1852: template deba@1852: class DefaultReader > deba@1852: : public InsertReader, deba@1852: DefaultReader > > {}; deba@1852: deba@1408: template deba@1408: class DefaultReader > deba@1408: : public InsertReader > {}; deba@1408: deba@1852: template deba@1852: class DefaultReader > deba@1852: : public InsertReader, deba@1852: DefaultReader > > {}; deba@1852: deba@1852: template deba@1852: class DefaultReader > deba@1852: : public PairReader > {}; deba@1852: alpar@1946: /// \ingroup item_io deba@1415: /// deba@1415: /// \brief The default item reader for skipping a value in the stream. deba@1415: /// deba@1415: /// The default item reader for skipping a value in the stream. deba@1415: /// deba@1415: /// \author Balazs Dezso deba@2254: class DefaultSkipper : public UnformattedReader {}; deba@1415: alpar@1946: /// \ingroup item_io deba@1408: /// \brief Standard ReaderTraits for the GraphReader class. deba@1408: /// deba@1408: /// Standard ReaderTraits for the GraphReader class. deba@1408: /// It defines standard reading method for all type of value. deba@1408: /// \author Balazs Dezso deba@1408: struct DefaultReaderTraits { deba@1408: deba@1408: template deba@1408: struct Reader : DefaultReader<_Value> {}; deba@1408: deba@1408: typedef DefaultSkipper Skipper; deba@1408: deba@1408: }; deba@1408: deba@1408: } deba@1408: deba@1408: #endif