Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | File List | Namespace Members | Class Members | File Members

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= 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 }

Generated on Tue Aug 17 16:01:25 2004 for PLearn by doxygen 1.3.7