PLearn 0.1
pl_streambuf.cc
Go to the documentation of this file.
00001 // -*- C++ -*-
00002 
00003 // PLearn (A C++ Machine Learning Library)
00004 // Copyright (C) 2002 Xavier Saint-Mleux <saintmlx@iro.umontreal.ca>
00005 //
00006 
00007 // Redistribution and use in source and binary forms, with or without
00008 // modification, are permitted provided that the following conditions are met:
00009 // 
00010 //  1. Redistributions of source code must retain the above copyright
00011 //     notice, this list of conditions and the following disclaimer.
00012 // 
00013 //  2. Redistributions in binary form must reproduce the above copyright
00014 //     notice, this list of conditions and the following disclaimer in the
00015 //     documentation and/or other materials provided with the distribution.
00016 // 
00017 //  3. The name of the authors may not be used to endorse or promote
00018 //     products derived from this software without specific prior written
00019 //     permission.
00020 // 
00021 // THIS SOFTWARE IS PROVIDED BY THE AUTHORS ``AS IS'' AND ANY EXPRESS OR
00022 // IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
00023 // OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
00024 // NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
00025 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
00026 // TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
00027 // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
00028 // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
00029 // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
00030 // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00031 // 
00032 // This file is part of the PLearn library. For more information on the PLearn
00033 // library, go to the PLearn Web site at www.plearn.org
00034 
00035 
00036 #include "pl_streambuf.h"
00037 
00038 
00039 using namespace PLearn;
00040 using namespace std;
00041 
00042 /*****
00043  * pl_streambuf
00044  */
00045 
00047 pl_streambuf::pl_streambuf(streambuf& _original_buf, int _inbuflen) 
00048     :original_buf(_original_buf), inbuf(0), inbuflen(_inbuflen), first_marker(0)
00049 {
00050     //set minimum size for buffer
00051     if(inbuflen < pback_size+1)
00052         inbuflen= min_buf_size + pback_size;
00053 
00054     inbuf= new char[inbuflen];
00055     setg(inbuf+pback_size, inbuf+pback_size, inbuf+pback_size); // reserve a few bytes for a putback area.
00056 }
00057 
00059 pl_streambuf::~pl_streambuf()
00060 {
00061     if(inbuf)
00062         delete[] inbuf;
00063 }
00064 
00067 pl_streambuf::int_type pl_streambuf::underflow()
00068 {
00069     //no marker: return get from original buffer.
00070     if(first_marker == 0 && gptr() == egptr())
00071     {
00072         //delete buffer if we have a long one that is not used anymore
00073         if(inbuflen > min_buf_size + pback_size)
00074         { //don't keep copy of last char: underlying buf. will be used for putbacks.
00075             delete[] inbuf;
00076             inbuflen= min_buf_size + pback_size;
00077             inbuf= new char[inbuflen];
00078             setg(inbuf+pback_size, inbuf+pback_size, inbuf+pback_size);
00079         }
00080         return original_buf.sgetc();
00081     }
00082   
00083     //marked buffer:
00084 
00085     //return a buffered char if any is available (is this necessary? -xsm)
00086     if(gptr() < egptr())
00087         return *gptr(); 
00088 
00089     int oldbuflen = int(egptr()-inbuf); //< current length used
00090     //if at end of buffer, make it twice as long as before
00091     if(egptr() == inbuf+inbuflen)
00092     {
00093         //create a new longer buffer
00094         int newbuflen= inbuflen*2;
00095         char* newbuf= new char[newbuflen];
00096       
00097         //copy from current buf. to new one
00098         for(int i= 0; i < inbuflen; ++i)
00099             newbuf[i]= inbuf[i];
00100 
00101         //reposition get pointers
00102         setg(newbuf+pback_size, newbuf+(gptr()-inbuf), newbuf+inbuflen);
00103         delete[] inbuf; //< delete prev. buffer
00104         inbuf= newbuf;  //< point to new buffer
00105         inbuflen= newbuflen; //< adjust current buffer length
00106     }
00107       
00108     char* the_egptr= 0;  //ptr. to actual end of buf. (not known yet)
00109 
00110     //fill buffer from underlying streambuf
00111     for(int i= oldbuflen; i < inbuflen; ++i)
00112         if((original_buf.sgetc() != pl_streambuf::eof && original_buf.in_avail()) || i == oldbuflen)
00113             inbuf[i]= original_buf.sbumpc();  //< get a char from underlying streambuf and advance it's pos.
00114         else
00115         { //no input available: stop filling buffer (set egptr at current pos)
00116             the_egptr= inbuf+i;
00117             break;
00118         }
00119 
00120     if(the_egptr == 0) //buf. all filled: set egptr at end of buf.
00121         the_egptr= inbuf + inbuflen;
00122 
00123     //set pointers into buffer
00124     setg(eback(), gptr(), the_egptr);
00125     if(gptr() < egptr()) //< got some new stuff?
00126         return *gptr();    //< return next char.
00127     return pl_streambuf::eof; //< at eof: return eof.
00128 }
00129 
00130 
00131 pl_streambuf::int_type pl_streambuf::uflow()
00132 {
00133     int c= underflow(); //< get char. at current pos.
00134     if(first_marker == 0 && gptr() == egptr()) 
00135         original_buf.sbumpc();  //< no mark: advance pos. of original streambuf
00136     else
00137         gbump(1);               //< mark(s): advance pos. in our buffer
00138     return c;
00139 }
00140 
00141 streamsize pl_streambuf::xsgetn(char_type* s, streamsize n)
00142 {
00143     int_type c= uflow();
00144     int i;
00145     for(i= 0; i < n && c != pl_streambuf::eof; ++i)
00146     {
00147         s[i]= static_cast<char_type>(c);
00148         c= uflow();
00149     }
00150     return i;
00151 }
00152 
00153 streamsize pl_streambuf::xsputn(const char_type* s, streamsize n)
00154 {
00155     int_type c = 1;
00156     int i;
00157     for(i= 0; i < n && c != pl_streambuf::eof; ++i)
00158         c= overflow(static_cast<int_type>(s[i]));
00159     return i;
00160 }
00161 
00162 
00163 pl_streambuf::int_type pl_streambuf::overflow(int_type meta) //trivial overflow
00164 { return original_buf.sputc(meta); }           //(no marking on output == no buffering)
00165 
00166 void pl_streambuf::seekmark(const pl_streammarker& mark)
00167 { setg(eback(), inbuf+mark.pos, egptr()); } //< set get ptr. to mark position
00168 
00169 pl_streambuf::int_type pl_streambuf::sync()
00170 { // no marking on output: sync underlying streambuf
00171 #if __GNUC__ < 3 && !defined(WIN32)
00172     return original_buf.sync();
00173 #else
00174     return original_buf.pubsync();
00175 #endif
00176 }
00177 
00178 pl_streambuf::int_type pl_streambuf::pbackfail(int_type c)
00179 { return original_buf.sungetc(); } //< pback before beginning of our buf: pback in underlying streambuf
00180 
00181 
00182 
00183 
00184 /*****
00185  * pl_streammarker
00186  */
00187 
00188 //ctor. from pl_streambuf: insert self in buf's list of markers and remember current pos.
00189 pl_streammarker::pl_streammarker(pl_streambuf* _buf)
00190     :buf(_buf), next_marker(buf->first_marker), pos(buf->curpos())
00191 { buf->first_marker= this; }
00192 
00193 //ctor. from any streambuf: just make sure it's a pl_streambuf and construct normally
00194 pl_streammarker::pl_streammarker(streambuf* _buf)
00195     :buf(dynamic_cast<pl_streambuf*>(_buf))
00196 {
00197     if(buf == 0)
00198         PLERROR("Cannot put a pl_streammarker on a streambuf that is not a pl_streambuf...");
00199     next_marker= buf->first_marker;
00200     pos= buf->curpos();
00201   
00202     buf->first_marker= this; 
00203 }
00204 
00205 //destructor: simply remove self from buf's list of markers.
00206 pl_streammarker::~pl_streammarker()
00207 {
00208     pl_streammarker* prev= 0; 
00209     for(pl_streammarker* it= buf->first_marker; it != 0; prev= it, it!=0?it= it->next_marker:it= 0)
00210         if(it == this)
00211         {
00212             if(prev == 0)
00213                 buf->first_marker= it->next_marker;
00214             else
00215                 prev->next_marker= it->next_marker;
00216             it= 0;
00217         }
00218 }
00219 
00220 
00221 /*
00222   Local Variables:
00223   mode:c++
00224   c-basic-offset:4
00225   c-file-style:"stroustrup"
00226   c-file-offsets:((innamespace . 0)(inline-open . 0))
00227   indent-tabs-mode:nil
00228   fill-column:79
00229   End:
00230 */
00231 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=79 :
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines