deba@1408: /* -*- C++ -*- ladanyi@1435: * lemon/bits/item_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@1415: /// @defgroup item_io Item Readers and Writers deba@1415: /// @ingroup io_group deba@1415: /// \brief Item Readers and Writers deba@1415: /// deba@1415: /// The Input-Output classes can handle more data type by example deba@1415: /// as map or attribute value. Each of these should be written and deba@1415: /// read some way. The module make possible to do this. deba@1415: deba@1415: /// \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@1408: deba@1408: namespace lemon { deba@1408: deba@1408: template deba@1408: class DefaultReader; deba@1408: deba@1415: /// \ingroup item_io deba@1408: /// 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@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@1408: if (!is.get(c) || c != '\"') deba@1408: throw DataFormatError("Quoted string format error"); deba@1408: while (is.get(c) && c != '\"') { deba@1408: if (escaped && c == '\\') { deba@1408: value += readEscape(is); deba@1408: } else { deba@1408: value += c; deba@1408: } deba@1408: } deba@1408: if (!is) throw DataFormatError("Quoted string 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: deba@1415: /// \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@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: is.putback(c); deba@1408: } deba@1408: deba@1408: }; deba@1408: deba@1415: /// \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@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: is.putback(c); deba@1408: } deba@1408: deba@1408: }; deba@1408: deba@1415: /// \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@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: deba@1415: /// \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@1408: void read(std::istream& is, Value& value) { deba@1408: if (skipSpaces) is >> std::ws; deba@1408: if (!getline(is, value)) { deba@1408: throw DataFormatError("LineReader forma error"); deba@1408: } deba@1408: } deba@1408: private: deba@1408: bool skipSpaces; deba@1408: }; deba@1408: deba@1415: /// \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@1429: if (!(is >> std::ws >> c)) return; deba@1427: is.putback(c); deba@1427: switch (c) { deba@1427: case '\"': deba@1427: QuotedStringReader().read(is, value); deba@1427: break; deba@1427: case '(': deba@1427: ParsedStringReader().read(is, value); deba@1427: break; deba@1744: case '[': deba@1744: ParsedStringReader('[', ']').read(is, value); deba@1744: break; deba@1744: case '/': deba@1744: ParsedStringReader('/', '/').read(is, value); deba@1744: break; deba@1427: default: deba@1744: if (!(is >> value)) deba@1744: throw DataFormatError("DefaultReader format error"); deba@1427: break; deba@1427: } deba@1427: } deba@1427: deba@1427: }; deba@1427: 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@1408: template deba@1408: class DefaultReader > deba@1408: : public InsertReader > {}; deba@1408: deba@1415: /// \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@1427: class DefaultSkipper : public DefaultReader {}; deba@1415: deba@1415: /// \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