CppCMS
cppcms/steal_buf.h
00001 
00002 //                                                                             
00003 //  Copyright (C) 2008-2012  Artyom Beilis (Tonkikh) <artyomtnk@yahoo.com>     
00004 //                                                                             
00005 //  See accompanying file COPYING.TXT file for licensing details.
00006 //
00008 #ifndef CPPCMS_STEAL_BUF_H
00009 #define CPPCMS_STEAL_BUF_H
00010 
00011 #include <streambuf>
00012 #include <ostream>
00013 #include <stdio.h>
00014 #include <string>
00015 #include <string.h>
00016 #include <stdlib.h>
00017 
00018 namespace cppcms {
00019 namespace util {
00020 
00031         template<size_t OnStackSize = 128>
00032         class stackbuf : public std::streambuf {
00033                 stackbuf(stackbuf const &);
00034                 void operator=(stackbuf const &);
00035         public:
00039                 char *begin()
00040                 {
00041                         return pbase();
00042                 }
00046                 char *end()
00047                 {
00048                         return pptr();
00049                 }
00053                 char *c_str()
00054                 {
00055                         *pptr() = 0;
00056                         return begin();
00057                 }
00061                 std::string str()
00062                 {
00063                         return std::string(begin(),size_t(end()-begin()));
00064                 }
00065                 stackbuf() 
00066                 {
00067                         init();
00068                 }
00069                 ~stackbuf()
00070                 {
00071                         free(on_heap_);
00072                 }
00073         protected:
00074 
00075                 int overflow(int c)
00076                 {
00077                         size_t current_size;
00078                         size_t new_size;
00079                         if(pbase() == on_stack_) {
00080                                 current_size = OnStackSize;
00081                                 new_size = OnStackSize * 2;
00082                                 on_heap_ = (char *)malloc(new_size + 1);
00083                                 if(!on_heap_)
00084                                         throw std::bad_alloc();
00085                                 memcpy(on_heap_,on_stack_,current_size);
00086                         }
00087                         else {
00088                                 current_size = pptr() - pbase();
00089                                 new_size = current_size * 2;
00090                                 char *new_ptr = (char *)realloc(on_heap_,new_size + 1);
00091                                 if(!new_ptr)
00092                                         throw std::bad_alloc();
00093                                 on_heap_ = new_ptr;
00094 
00095                         }
00096                         setp(on_heap_,on_heap_ + new_size);
00097                         pbump(current_size);
00098                         if(c!=EOF)
00099                                 sputc(c);
00100                         return 0;
00101                 }
00102         private:
00103                 void init()
00104                 {
00105                         on_heap_ = 0;
00106                         setp(on_stack_,on_stack_+OnStackSize);
00107                 }
00108                 char *on_heap_;
00109                 char on_stack_[OnStackSize + 1];
00110         };
00111 
00112 
00125         template<size_t Size = 128>
00126         class steal_buffer : public stackbuf<Size> {
00127         public:
00131                 steal_buffer(std::ostream &out) 
00132                 {
00133                         stolen_ = 0;
00134                         stream_ = 0;
00135                         steal(out);
00136                 }
00140                 steal_buffer() 
00141                 {
00142                         stolen_ = 0;
00143                         stream_ = 0;
00144                 }
00148                 void steal(std::ostream &out)
00149                 {
00150                         release();
00151                         stolen_ = out.rdbuf(this);
00152                         stream_ = &out;
00153                 }
00158                 void release()
00159                 {
00160                         if(stream_ && stolen_) {
00161                                 stream_->rdbuf(stolen_);
00162                         }
00163                         stream_ = 0;
00164                         stolen_ = 0;
00165                 }
00166                 ~steal_buffer()
00167                 {
00168                         release();
00169                 }
00170         private:
00171                 std::streambuf *stolen_;
00172                 std::ostream *stream_;
00173         };
00174 
00182         template<size_t Size = 128>
00183         class stackstream : public std::ostream {
00184         public:
00188                 stackstream() : std::ostream(0)
00189                 {
00190                         rdbuf(&buf_);
00191                 }
00195                 char *begin()
00196                 {
00197                         return buf_.begin();
00198                 }
00202                 char *end()
00203                 {
00204                         return buf_.end();
00205                 }
00209                 char *c_str()
00210                 {
00211                         return buf_.c_str();
00212                 }
00216                 std::string str()
00217                 {
00218                         return buf_.str();
00219                 }
00220         private:
00221                 stackbuf<Size> buf_;
00222         };
00223         
00224 } // util
00225 } // cppcms
00226 
00227 #endif