charstream.hpp

00001 /*
00002 This file is part of GraphLab.
00003 
00004 GraphLab is free software: you can redistribute it and/or modify
00005 it under the terms of the GNU Lesser General Public License as 
00006 published by the Free Software Foundation, either version 3 of 
00007 the License, or (at your option) any later version.
00008 
00009 GraphLab is distributed in the hope that it will be useful,
00010 but WITHOUT ANY WARRANTY; without even the implied warranty of
00011 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012 GNU Lesser General Public License for more details.
00013 
00014 You should have received a copy of the GNU Lesser General Public 
00015 License along with GraphLab.  If not, see <http://www.gnu.org/licenses/>.
00016 */
00017 
00018 #ifndef GRAPHLAB_CHARSTREAM
00019 #define GRAPHLAB_CHARSTREAM
00020 
00021 #include <boost/iostreams/stream.hpp>
00022 #include <boost/iostreams/categories.hpp>
00023 
00024 namespace graphlab {
00025 
00026   /// \ingroup util_internal
00027   namespace charstream_impl {
00028     /// \ingroup util_internal
00029     template <bool self_deleting>
00030     struct resizing_array_sink {
00031 
00032 
00033       resizing_array_sink(size_t initial = 0) : str(NULL) { 
00034         if(initial > 0) {
00035           str = (char*)(malloc(initial));
00036           assert(str != NULL);
00037         } 
00038         len = 0;
00039         buffer_size = initial;
00040       }
00041 
00042       resizing_array_sink(const resizing_array_sink& other) :
00043         len(other.len), buffer_size(other.buffer_size) {
00044         if(self_deleting) {
00045           str = (char*)(malloc(other.buffer_size));
00046           assert(str != NULL);
00047           memcpy(str, other.str, len);
00048         } else {
00049           str = other.str;
00050         }
00051       }
00052 
00053       ~resizing_array_sink() {
00054         if( self_deleting && str != NULL) {
00055           free((void*)str);
00056         }        
00057       }
00058 
00059 
00060       size_t size() const { return len; }
00061       char* c_str() { return str; }
00062 
00063       void clear() {
00064         len = 0;
00065       }
00066 
00067       char *str;
00068       size_t len;
00069       size_t buffer_size;
00070       typedef char        char_type;
00071       struct category: public boost::iostreams::device_tag,
00072                        public boost::iostreams::output,
00073                        public boost::iostreams::multichar_tag { };
00074       
00075       /** the optimal buffer size is 0. */
00076       inline std::streamsize optimal_buffer_size() const { return 0; }
00077       
00078       inline std::streamsize write(const char* s, std::streamsize n) {
00079         if (len + n > buffer_size) {
00080           // double in length if we need more buffer
00081           buffer_size = 2 * (len + n);
00082           str = (char*)realloc(str, buffer_size);
00083           assert(str != NULL);
00084         }
00085         memcpy(str + len, s, n);
00086         len += n;
00087         return n;
00088       }
00089     };
00090 
00091   }; // end of impl;
00092   
00093   
00094   /**
00095    * \ingroup util
00096    * A stream object which stores all streamed output in memory.
00097    * It can be used like any other stream object.
00098    * For instance:
00099    * \code
00100    *  charstream cstrm;
00101    *  cstrm << 123 << 10.0 << "hello world" << std::endl;
00102    * \endcode
00103    *
00104    * stream->size() will return the current length of output
00105    * and stream->c_str() will return a mutable pointer to the string.
00106    */
00107   typedef boost::iostreams::stream< charstream_impl::resizing_array_sink<true> > 
00108   charstream;
00109 
00110 
00111 }; // end of namespace graphlab
00112 #endif
00113