deba@1409: /* -*- C++ -*-
deba@1409:  *
alpar@1956:  * This file is a part of LEMON, a generic C++ optimization library
alpar@1956:  *
alpar@2391:  * Copyright (C) 2003-2007
alpar@1956:  * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
alpar@1956:  * (Egervary Research Group on Combinatorial Optimization, EGRES).
deba@1409:  *
deba@1409:  * Permission to use, modify and distribute this software is granted
deba@1409:  * provided that this copyright notice appears in all copies. For
deba@1409:  * precise terms see the accompanying LICENSE file.
deba@1409:  *
deba@1409:  * This software is provided "AS IS" with no warranty of any kind,
deba@1409:  * express or implied, and with no claim as to its suitability for any
deba@1409:  * purpose.
deba@1409:  *
deba@1409:  */
deba@1409: 
alpar@1946: /// \ingroup item_io
deba@1409: /// \file
deba@1409: /// \brief Item writer bits for lemon output.
deba@1409: 
deba@1409: #ifndef LEMON_BITS_ITEM_WRITER_H
deba@1409: #define LEMON_BITS_ITEM_WRITER_H
deba@1409: 
deba@1409: #include <iostream>
deba@2254: #include <sstream>
deba@1409: #include <string>
deba@1409: 
deba@1409: #include <vector>
deba@1409: #include <deque>
deba@1409: #include <list>
deba@1409: #include <set>
deba@2426: #include <map>
deba@2426: 
deba@2426: #include <lemon/error.h>
deba@1409: 
deba@1409: namespace lemon {
deba@1409:   
deba@1409:   template <typename Value>
deba@1409:   class DefaultWriter;
deba@1409: 
alpar@1946:   /// \ingroup item_io
deba@1409:   /// \brief Writer class for quoted strings.
deba@1409:   ///
deba@2254:   /// Writer class for unformatted strings.
deba@2254:   /// \author Balazs Dezso
deba@2254:   class UnformattedWriter {
deba@2254:   public:
deba@2254:     typedef std::string Value;
deba@2254: 
deba@2254:     /// \brief Constructor for the writer.
deba@2254:     ///
deba@2254:     /// Constructor for the writer.
deba@2254:     UnformattedWriter() {}
deba@2254: 
deba@2254:     /// \brief Writes an unformatted string to the given stream.
deba@2254:     ///
deba@2254:     /// Writes an unformatted string to the given stream.
deba@2254:     void write(std::ostream& os, const std::string& value) const {
deba@2254:       os << value;
deba@2254:     }
deba@2254: 
deba@2254:     bool readable(const std::string& value) const {
deba@2254:       std::istringstream is(value);
deba@2254:       char c;
deba@2254:       while (is.get(c) && !whiteSpace(c)) {
deba@2254:         if (!processChar(c, is)) return false;
deba@2254:       }
deba@2254:       if (is) return false;
deba@2254:       return true;
deba@2254:     }
deba@2254: 
deba@2254:   private:
deba@2254: 
deba@2254:     bool processChar(char c, std::istream& is) const {
deba@2254:       switch (c) {
deba@2254:       case '(':
deba@2254:         is.putback(c);
deba@2254:         if (!readableParsed('(', ')', is)) return false;
deba@2254:         break;
deba@2254:       case '[':
deba@2254:         is.putback(c);
deba@2254:         if (!readableParsed('[', ']', is)) return false;
deba@2254:         break;
deba@2254:       case '{':
deba@2254:         is.putback(c);
deba@2254:         if (!readableParsed('{', '}', is)) return false;
deba@2254:         break;
deba@2255:       case '/':
deba@2255:         is.putback(c);
deba@2255:         if (!readableParsed('/', '/', is)) return false;
deba@2255:         break;
deba@2254:       case '\"':
deba@2254:         is.putback(c);
deba@2254:         if (!readableQuoted('\"', is)) return false;
deba@2254:         break;
deba@2254:       case '\'':
deba@2254:         is.putback(c);
deba@2254:         if (!readableQuoted('\'', is)) return false;
deba@2254:         break;
deba@2254:       default:
deba@2254:         break;
deba@2254:       }
deba@2254:       return true;
deba@2254:     }
deba@2254: 
deba@2254:     bool readableParsed(char open, char close, std::istream& is) const {
deba@2254:       char c;
deba@2254:       if (!is.get(c) || c != open) return false;
deba@2254:       while (is.get(c) && c != close) {
deba@2254:         if (!processChar(c, is)) return false;
deba@2254:       }
deba@2254:       if (!is) return false;
deba@2254:       return true;
deba@2254:     }
deba@2254: 
deba@2254:     bool readableQuoted(char quote, std::istream& is) const {
deba@2254:       char c;
deba@2254:       bool esc = false;
deba@2254:       if (!is.get(c) || c != quote) return false;
deba@2255:       while (is.get(c) && (c != quote || esc)) {
deba@2254:         if (c == '\\') esc = !esc;
deba@2254:         else esc = false;
deba@2254:       }
deba@2254:       if (!is) return false;
deba@2254:       return true;
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:   /// \ingroup item_io
deba@2254:   /// \brief Writer class for quoted strings.
deba@2254:   ///
deba@1409:   /// Writer class for quoted strings. It can process the escape
deba@1409:   /// sequences in the string.
deba@1409:   /// \author Balazs Dezso
deba@1409:   class QuotedStringWriter {
deba@2254:     friend class QuotedCharWriter;
deba@1409:   public:
deba@1409:     typedef std::string Value;
deba@1409: 
deba@1409:     /// \brief Constructor for the writer.
deba@1409:     ///
deba@1409:     /// Constructor for the writer. If the given parameter is true
deba@1409:     /// the writer creates escape sequences from special characters.
deba@2426:     QuotedStringWriter(bool _escaped = true, char _quote = '\"') 
deba@2426:       : escaped(_escaped), quote(_quote) {}
deba@1409: 
deba@1409:     /// \brief Writes a quoted string to the given stream.
deba@1409:     ///
deba@1409:     /// Writes a quoted string to the given stream.
deba@1852:     void write(std::ostream& os, const std::string& value) const {
deba@2426:       os << quote;
deba@1409:       if (escaped) {
klao@1535: 	std::ostringstream ls;
deba@2386: 	for (int i = 0; i < int(value.size()); ++i) {
deba@1409: 	  writeEscape(ls, value[i]);
deba@1409: 	}
deba@1409: 	os << ls.str();
deba@1409:       } else {
deba@1409: 	os << value;
deba@1409:       }
deba@2426:       os << quote;
deba@1409:     }
deba@1409: 
deba@1409:   private:
deba@1409:     
deba@1409:     static void writeEscape(std::ostream& os, char c) {
deba@1409:       switch (c) {
deba@1409:       case '\\':
deba@1409: 	os << "\\\\";
deba@1409: 	return;
deba@1409:       case '\"':
deba@1409: 	os << "\\\"";
deba@1409: 	return;
deba@1409:       case '\'':
deba@1409: 	os << "\\\'";
deba@1409: 	return;
deba@1409:       case '\?':
deba@1409: 	os << "\\\?";
deba@1409: 	return;
deba@1409:       case '\a':
deba@1409: 	os << "\\a";
deba@1409: 	return;
deba@1409:       case '\b':
deba@1409: 	os << "\\b";
deba@1409: 	return;
deba@1409:       case '\f':
deba@1409: 	os << "\\f";
deba@1409: 	return;
deba@1409:       case '\r':
deba@1409: 	os << "\\r";
deba@1409: 	return;
deba@1409:       case '\n':
deba@1409: 	os << "\\n";
deba@1409: 	return;
deba@1409:       case '\t':
deba@1409: 	os << "\\t";
deba@1409: 	return;
deba@1409:       case '\v':
deba@1409: 	os << "\\v";
deba@1409: 	return;
deba@1409:       default:
deba@1409: 	if (c < 0x20) {
deba@2386: 	  os << '\\' << std::oct << static_cast<int>(c);
deba@1409: 	} else {
deba@1409: 	  os << c;
deba@1409: 	}
deba@1409: 	return;
deba@1409:       }     
deba@1409:     }
deba@1409:   private:
deba@1409:     bool escaped;
deba@2426:     char quote;
deba@1409:   };
deba@1409: 
alpar@1946:   /// \ingroup item_io
deba@2254:   /// \brief Writer class for quoted chars.
deba@2254:   ///
deba@2254:   /// Writer class for quoted char. It can process the escape
deba@2254:   /// sequences in the string.
deba@2254:   /// \author Balazs Dezso
deba@2254:   class QuotedCharWriter {
deba@2254:   public:
deba@2254:     typedef char Value;
deba@2254: 
deba@2254:     /// \brief Constructor for the writer.
deba@2254:     ///
deba@2254:     /// Constructor for the writer. If the given parameter is true
deba@2254:     /// the writer creates escape sequences from special characters.
deba@2254:     QuotedCharWriter(bool _escaped = true) : escaped(_escaped) {}
deba@2254: 
deba@2254:     /// \brief Writes a quoted char to the given stream.
deba@2254:     ///
deba@2254:     /// Writes a quoted char to the given stream.
deba@2254:     void write(std::ostream& os, const char& value) const {
deba@2254:       os << "\'";
deba@2254:       if (escaped) {
deba@2254: 	std::ostringstream ls;
deba@2254:         QuotedStringWriter::writeEscape(ls, value);
deba@2254: 	os << ls.str();
deba@2254:       } else {
deba@2254: 	os << value;
deba@2254:       }
deba@2254:       os << "\'";
deba@2254:     }
deba@2254: 
deba@2254:   private:
deba@2254:     bool escaped;
deba@2254:   };
deba@2254: 
deba@2254:   /// \ingroup item_io
deba@1533:   /// \brief Writer class for quoted char array.
deba@1533:   ///
deba@1533:   /// Writer class for quoted char array. It can process the escape
deba@1533:   /// sequences in the char array.
deba@1533:   /// \author Balazs Dezso
deba@1533:   class QuotedCharArrayWriter {
deba@1533:   public:
deba@1533:     typedef const char* Value;
deba@1533: 
deba@1533:     /// \brief Constructor for the writer.
deba@1533:     ///
deba@1533:     /// Constructor for the writer. If the given parameter is true
deba@1533:     /// the writer creates escape sequences from special characters.
deba@1533:     QuotedCharArrayWriter(bool _escaped = true) : escaped(_escaped) {}
deba@1533: 
deba@1533:     /// \brief Writes a quoted char array to the given stream.
deba@1533:     ///
deba@1533:     /// Writes a quoted char array to the given stream.
deba@1852:     void write(std::ostream& os, const char* value) const {
deba@1533:       QuotedStringWriter(escaped).write(os, std::string(value));
deba@1533:     }
deba@1533: 
deba@1533:   private:    
deba@1533:     bool escaped;
deba@1533:   };
deba@1533: 
deba@1533: 
alpar@1946:   /// \ingroup item_io
deba@1409:   ///
deba@1409:   /// \brief Writer for standard containers.
deba@1409:   ///
deba@1409:   /// Writer for each iterable standard containers. The representation
deba@1409:   /// of the container is the values enumerated between an open and a
deba@1409:   /// close parse. 
deba@1409:   ///
deba@1409:   /// \author Balazs Dezso
deba@1409:   template <
deba@1409:     typename _Container, 
deba@1409:     typename _ItemWriter = DefaultWriter<typename _Container::value_type> 
deba@1409:   >
deba@1409:   class IterableWriter {
deba@1409:   public:
deba@1409:     typedef _Container Value;
deba@1409:     typedef _ItemWriter ItemWriter;
deba@1409: 
deba@1409:   private:
deba@1409: 
deba@1409:     ItemWriter item_writer;
deba@1409: 
deba@1409:   public:
deba@1409: 
deba@1852:     IterableWriter(const ItemWriter& _item_writer = ItemWriter())
deba@1852:       : item_writer(_item_writer) {}
deba@1852: 
deba@1409:     /// \brief Writes the values of the container to the given stream.
deba@1409:     ///
deba@1409:     /// Writes the values of the container to the given stream.
deba@1409:     void write(std::ostream& os, const Value& value) const {
deba@1409:       typename Value::const_iterator it;
deba@1409:       os << '(';
deba@1409:       for (it = value.begin(); it != value.end(); ++it) {
deba@1409: 	item_writer.write(os, *it);
deba@1409: 	os << ' ';
deba@1409:       }
deba@1409:       os << ')';
deba@1409:     }
deba@1409: 
deba@1409:   };
deba@1409: 
alpar@1946:   /// \ingroup item_io
deba@1852:   ///
deba@1852:   /// \brief Writer for standard pairs.
deba@1852:   ///
deba@1852:   /// Writer for standard pairs. The representation of a pair is
alpar@1946:   ///\code ( first_value => second_value ) \endcode.
deba@1852:   /// \author Balazs Dezso
deba@1852:   template <typename _Pair, 
deba@1852: 	    typename _FirstWriter = 
deba@1852: 	    DefaultWriter<typename _Pair::first_type>,
deba@1852: 	    typename _SecondWriter = 
deba@1852: 	    DefaultWriter<typename _Pair::second_type> >
deba@1852:   class PairWriter {
deba@1852:   public:
deba@1852: 
deba@1852:     typedef _Pair Value;
deba@1852: 
deba@1852:     typedef _FirstWriter FirstWriter;
deba@1852:     typedef _SecondWriter SecondWriter;
deba@1852: 
deba@1852:   private:
deba@1852: 
deba@1852:     FirstWriter first_writer;
deba@1852:     SecondWriter second_writer;
deba@1852: 
deba@1852:   public:
deba@1852:     
deba@1852:     /// \brief Constructor.
deba@1852:     ///
deba@1852:     /// Constructor for the PairWriter.
deba@1852:     PairWriter(const FirstWriter& _first_writer = FirstWriter(), 
deba@1852: 	       const SecondWriter& _second_writer = SecondWriter()) 
deba@1852:       : first_writer(_first_writer), second_writer(_second_writer) {}
deba@1852:     
deba@1852:     /// \brief Writes the pair from the given stream.
deba@1852:     ///
deba@1852:     /// Writes the pair from the given stream.
deba@1852:     void write(std::ostream& os, const Value& value) const {
deba@1852:       os << "( ";
deba@1852:       first_writer.write(os, value.first);
deba@1852:       os << " => ";
deba@1852:       second_writer.write(os, value.second);
deba@1852:       os << " )";
deba@1852:     }
deba@1852: 
deba@1852:   };
deba@1852: 
alpar@1946:   /// \ingroup item_io
deba@1409:   /// 
deba@1409:   /// \brief The default item writer template class.
deba@1409:   ///
deba@1409:   /// The default item writer template class. If some section writer
deba@1409:   /// needs to write a value to the stream it will give the default way for it.
deba@1409:   ///
deba@1409:   /// \author Balazs Dezso
deba@1409:   template <typename _Value>
deba@1409:   class DefaultWriter {
deba@1409:   public:
deba@1409:     /// The value type.
deba@1409:     typedef _Value Value;
deba@1409:     /// \brief Writes the value to the given stream.
deba@1409:     ///
deba@1409:     /// Writes the value to the given stream.
deba@1409:     void write(std::ostream& os, const Value& value) const {
deba@1409:       os << value;
deba@1409:     }
deba@1409:   };
deba@1409: 
deba@1429:   template <>
deba@2254:   class DefaultWriter<std::string> {
deba@2254:   public:
deba@2254:     typedef std::string Value;
deba@2254:     
deba@2254:     void write(std::ostream& os, const Value& value) const {
deba@2254:       if (UnformattedWriter().readable(value)) {
deba@2254:         UnformattedWriter().write(os, value);
deba@2254:       } else {
deba@2254:         QuotedStringWriter().write(os, value);
deba@2254:       }
deba@2254:     }
deba@2254:       
deba@2254:   };
deba@2254: 
deba@2254:   template <>
deba@2254:   class DefaultWriter<char> 
deba@2254:     : public QuotedCharWriter {};
deba@2254: 
deba@2254:   template <>
deba@2254:   class DefaultWriter<bool> {
deba@2254:   public:
deba@2254:     typedef bool Value;
deba@2254:     
deba@2254:     void write(std::ostream& os, const Value& value) const {
deba@2254:       os << (value ? "1" : "0");
deba@2254:     }
deba@2254:       
deba@2254:   };
deba@1429: 
deba@1533:   template <int length>
deba@1533:   class DefaultWriter<char[length]> 
deba@1533:     : public QuotedCharArrayWriter {};
deba@1533: 
deba@1533:   template <int length>
deba@1533:   class DefaultWriter<const char[length]> 
deba@1533:     : public QuotedCharArrayWriter {};
deba@1533: 
deba@1852:   template <>
deba@1852:   class DefaultWriter<char*> 
deba@1852:     : public QuotedCharArrayWriter {};
deba@1852: 
deba@1852:   template <>
deba@1852:   class DefaultWriter<const char*> 
deba@1852:     : public QuotedCharArrayWriter {};
deba@1852: 
deba@1409:   template <typename Item>
deba@1409:   class DefaultWriter<std::vector<Item> > 
deba@1409:     : public IterableWriter<std::vector<Item> > {};
deba@1409: 
deba@1409:   template <typename Item>
deba@1409:   class DefaultWriter<std::deque<Item> > 
deba@1409:     : public IterableWriter<std::deque<Item> > {};
deba@1409: 
deba@1409:   template <typename Item>
deba@1409:   class DefaultWriter<std::list<Item> > 
deba@1409:     : public IterableWriter<std::list<Item> > {};
deba@1409:   
deba@1409:   template <typename Item>
deba@1409:   class DefaultWriter<std::set<Item> > 
deba@1409:     : public IterableWriter<std::set<Item> > {};
deba@1409: 
deba@1852:   template <typename Key, typename Value>
deba@1852:   class DefaultWriter<std::map<Key, Value> > 
deba@1852:     : public IterableWriter<std::map<Key, Value> > {};
deba@1852: 
deba@1409:   template <typename Item>
deba@1409:   class DefaultWriter<std::multiset<Item> > 
deba@1409:     : public IterableWriter<std::multiset<Item> > {};
deba@1409: 
deba@1852:   template <typename Key, typename Value>
deba@1852:   class DefaultWriter<std::multimap<Key, Value> > 
deba@1852:     : public IterableWriter<std::multimap<Key, Value> > {};
deba@1852: 
deba@1852:   template <typename First, typename Second>
deba@1852:   class DefaultWriter<std::pair<First, Second> > 
deba@1852:     : public PairWriter<std::pair<First, Second> > {};
deba@1852: 
alpar@1946:   /// \ingroup item_io
deba@1409:   /// \brief Standard WriterTraits for the section writers.
deba@1409:   ///
deba@1409:   /// Standard WriterTraits for the section writers.
deba@1409:   /// It defines standard writing method for all type of value. 
deba@1409:   /// \author Balazs Dezso
deba@1409:   struct DefaultWriterTraits {
deba@1409: 
deba@1409:     template <typename _Value>
deba@1533:     struct Writer : DefaultWriter<_Value> {
deba@1533:       typedef DefaultWriter<_Value> Parent;
deba@1533:     };
deba@1409: 
deba@1409:   };
deba@1409: 
deba@1409: }
deba@1409: 
deba@1409: #endif